diff --git "a/app/zh/blogs/wangshanshan/IndexOnlyScan\346\237\245\350\257\242\347\273\223\346\236\234\345\274\202\345\270\270.md" "b/app/zh/blogs/wangshanshan/IndexOnlyScan\346\237\245\350\257\242\347\273\223\346\236\234\345\274\202\345\270\270.md" new file mode 100644 index 0000000000000000000000000000000000000000..97975be6c28da505842922bbf97b1bcb8df1c0a7 --- /dev/null +++ "b/app/zh/blogs/wangshanshan/IndexOnlyScan\346\237\245\350\257\242\347\273\223\346\236\234\345\274\202\345\270\270.md" @@ -0,0 +1,132 @@ +--- +title: '一次线上查询结果问题分析诊断:Index Only Scan查询结果异常' +date: '2023-08-25' +category: 'blog' +tags: ['openGauss社区开发入门'] +archives: '2023-08' +author: 'wangshanshan' +summary: '一次线上查询结果问题分析诊断:Index Only Scan查询结果异常' +img: '' +times: '10:30' +--- +中国移动磐维数据是基于openGauss定制开发的中国移动自用版OLTP数据库。自去年12月发布以来,受到广泛关注,目前已成功上线百余套。 +在产品落地的过程中,我们积累了大量的迁移、适配,以及问题分析诊断的经验。 +本文分享我们在用户环境发现的一个数据查询结果异常问题的分析诊断过程。 + +社区issue:https://gitee.com/opengauss/openGauss-server/issues/I72FHP +## **【1. 问题现象】** +### 用户环境 + - 系统环境:openEuler 20.03_x86 + - 数据库版本:PanWeiDB 1.0.0(基于openGauss v3.0.1) +### 现象描述 +查询表记录数,通过表扫描(Seq Scan)和纯索引扫描(Index Only Scan),查询结果不一致,如下图所示: + +![img_1.png](./images/img_1.png) +## **【2. 场景分析】** +1. 表上定义有btree索引。 +2. 表上有较高并发的写,更新表和索引。 +3. 对表进行vacuum freeze后索引数据不一致问题恢复,但有warning报错,如下图所示: + +![img_2.png](./images/img_2.png) +## **【3. 问题复现】** +### 复现思路 +1. 采用用户环境相同的数据库配置。 +2. 创建表和btree索引,插入测试数据。 +3. 并发执行两组写: + - 多次更新某一条数据,不涉及索引更新。 + - 多次更新某一条数据,每次都更加索引键值。 +### 测试用例 + 1. 创建用户、数据库、模式 + create user testusr password 'Test@123'; + grant all privileges to testusr; + \c postgres + drop database if exists testdb; + create database testdb; + \c testdb + create schema wss_test; + set search_path to wss_test; + + 2. 编译 + javac -cp .jar insert.java update_dup.java update_diff.java + + 3. 执行insert(建表、索引,插入测试数据) + java -cp .:postgresql.jar insert + + 4. 多次执行update_dup(多次更新某一条数据,不涉及索引更新) + java -cp .:postgresql.jar update_dup + + 5. 查看count(*)执行计划,确保为Index Only Scan + select count(*) from wss_test.t_m_resource_monitor_test2; + explain analyze select count(*) from wss_test.t_m_resource_monitor_test2; + + 6. 多次执行update_diff和update_dup + java -cp .:postgresql.jar update_diff(多次更新某一条数据,每次都更加索引键值) + java -cp .:postgresql.jar update_dup(多次更新某一条数据,不涉及索引更新) + + 7. 在主从节点查询count(*),可以看到主从节点查询结果出现差异 + select count(*) from wss_test.t_m_resource_monitor_test2; + explain analyze select count(*) from wss_test.t_m_resource_monitor_test2; +[insert.java](./files/insert.java) + +[update_dup.java](./files/update_dup.java) + +[update_diff.java](./files/update_diff.java) +### 复现结果 +#### 主节点 + +![img_3.png](./images/img_3.png) +#### 备节点 + +![img_4.png](./images/img_4.png) +### 复现说明 +1. 复现过程中发现,主节点查询结果始终正确,仅备节点查询结果出现不一致。 +2. 仅在PanWeiDB 1.0.0(基于opengauss v3.0.1)复现,PanWeiDB 2.0.0(基于opengauss v5.0.0)未复现。 +## **【4. 问题诊断】** +由于结果出现偏差的是备节点的Index Only Scan查询,所以排查该查询计划的优化逻辑, +发现Index Only Scan查询使用了数据表的VM(visibility map)文件来判断数据元组的可见性, +即是否应该包含在结果集当中,因此怀疑VM文件的数据页可见性标志位是否准确。 +1. 查询数据表和索引的filepath。 + +![img_5.png](./images/img_5.png) +2. 用pagehack工具打印数据表,查看数据页标志位,发现主备节点有PD_ALL_VISIBLE标志的数据页均为42个。 + +```./pagehack -f /data/pwdb/data/base/24597/50856 -t heap -v``` + +![img_6.png](./images/img_6.png) +3. 用pagehack工具用十六进制的方式打印VM文件,查看数据页可见性标志位,发现主节点为42个完全可见页,备节点有72个。 + +## **【5. 代码分析】** +由上述诊断可见,确实是备节点VM文件数据页可见性标志位的问题导致了备节点Index Only Scan查询结果出现偏差, +因此怀疑备节点VM文件的数据页可见性标志位修改(清理)逻辑是否有问题。 +1. 相关的VM修改接口如下图所示: + +![img_7.png](./images/img_7.png) + +![img_8.png](./images/img_8.png) +2. 由于复现过程中仅涉及insert、update两类操作,因此主要排查这两类xlog日志回放逻辑, +其中clear清除接口在备节点回放insert、update xlog日志时都会被调用。 + +![img_10.png](./images/img_10.png) +3. 回放update时,会从update xlog日志头位置添加两个偏移量,分别是sizeof(TransactionId)和sizeof(CommitSeqNo), +然后读取日志的标志位,根据标志位判断是否修改VM文件,清理数据页可见性标志位,如下图所示: + +![img_12.png](./images/img_12.png) +4. 然而在写update xlog日志时,CommitSeqNo字段写入位置是在日志数据的尾部,如下图所示: + +![img.png](./images/img.png) + +经排查发现,由于PanWeiDB 1.0.0(基于opengauss v3.0.1)在实现并行逻辑解码功能时, +在执行DML操作时会在xlog的末尾追加写入CommitSeqNo(CSN),备节点回放xlog时读取,用于逻辑解码。 +但heap_xlog_update接口读取xlog时误认为CSN在xlog的头部,因此添加了该字段的偏移量来获取标志位, +根据标志位判断是否修改VM文件,清理数据页可见性标志位,导致备节点的VM文件错误。 +相关逻辑仅在wal_level设置为logical时生效,且若主备发生切换,该问题在主节点也有几率出现,与用户场景相符。 +## **【6. 代码修复】** +1. 删除heap_xlog_update接口中添加长度为sizeof(CommitSeqNo)的偏移量的代码。 +2. openGauss 3.1.0已修复该问题,但没有bug相关的描述,提交记录如下: +https://gitee.com/opengauss/openGauss-server/commit/b919f404e8d9acff1824d299dccecd9f2c741b43 +## **【7. 解决方案】** +1. 该问题只wal_level设置为logical的情况下才会发生,若无需使用逻辑复制功能,可以将wal_level设置为hot_standby并对主备节点执行vacuum。 +2. 或者关闭enable_indexonlyscan参数,禁用纯索引扫描,一般情况下实际生产环境中能使用Index Only Scan的情况比较少,可以考虑在用户环境关闭该参数后测试影响。 +3. 彻底修复客户环境问题,可以考虑代码修复合入后,打补丁或者大版本升级。 +## **【8. 致谢】** +感谢海量数据库内核专家协助分析! \ No newline at end of file diff --git a/app/zh/blogs/wangshanshan/files/insert.java b/app/zh/blogs/wangshanshan/files/insert.java new file mode 100644 index 0000000000000000000000000000000000000000..1a709d53a27857889defc6527128249d40722908 --- /dev/null +++ b/app/zh/blogs/wangshanshan/files/insert.java @@ -0,0 +1,299 @@ +//insert.java +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.ResultSet; +import java.io.*; + +public class insert { + + //创建数据库连接。 + public static Connection GetConnection(String username, String passwd) { + String driver = "org.postgresql.Driver"; + String sourceURL = "jdbc:postgresql://127.0.0.1:5432/testdb"; + Connection conn = null; + try { + //加载数据库驱动。 + Class.forName(driver).newInstance(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + try { + //创建数据库连接。 + conn = DriverManager.getConnection(sourceURL, username, passwd); + System.out.println("Connection succeed!"); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + return conn; + } + + //执行普通SQL语句,查询测试表。 + public static void QueryTable(Connection conn) { + Statement stmt = null; + try { + stmt = conn.createStatement(); + //执行普通SQL语句。 + stmt.setFetchSize(50); + + int ret = 0; + + ret = stmt.executeUpdate("drop table if exists wss_test.t_m_resource_monitor_test2;"); + ret = stmt.executeUpdate("CREATE TABLE wss_test.t_m_resource_monitor_test2 (\n" + + "\tid varchar(36) NOT NULL,\n" + + "\tip varchar(50) NOT NULL DEFAULT '',\n" + + "\tipv6 varchar(50) NOT NULL DEFAULT '',\n" + + "\tfull_ipv6 varchar(50) NOT NULL DEFAULT '',\n" + + "\ttarget_ip varchar(50) NOT NULL DEFAULT '',\n" + + "\tname varchar(1024) NULL,\n" + + "\tresource_name varchar(1024) NULL,\n" + + "\talias varchar(1024) NULL,\n" + + "\tmodel_id varchar(36) NULL,\n" + + "\tmodel_name varchar(150) NULL,\n" + + "\tis_model int4 NOT NULL,\n" + + "\tgroup_id varchar(36) NULL,\n" + + "\tgroup_name varchar(150) NULL,\n" + + "\tconf_group varchar(32) NULL,\n" + + "\tlogo_id varchar(64) NULL,\n" + + "\timage_base64 text NULL,\n" + + "\tmonitor_item int4 NULL,\n" + + "\tgather_strategy int4 NULL,\n" + + "\talarm_strategy int4 NULL,\n" + + "\tstate int4 NULL DEFAULT 0,\n" + + "\tauto_state int4 NULL DEFAULT 1,\n" + + "\trelation_state int4 NULL DEFAULT 1,\n" + + "\tamdb_state varchar(64) NULL,\n" + + "\tmodifier varchar(64) NULL DEFAULT 'admin'::character varying,\n" + + "\tmodify_time timestamp(6) NULL,\n" + + "\tcreater varchar(64) NULL DEFAULT 'admin'::character varying,\n" + + "\tcreate_time timestamp(6) NULL,\n" + + "\tdisplay int4 NULL DEFAULT 1,\n" + + "\tappchecker_state int4 NULL DEFAULT 0,\n" + + "\tagent_state int4 NULL DEFAULT 0,\n" + + "\tobserve_state int4 NULL DEFAULT 3,\n" + + "\tmanual_state int4 NULL DEFAULT -1,\n" + + "\tagent_process_info varchar(1024) DEFAULT NULL,\n" + + "\tagent_version varchar(64) DEFAULT NULL,\n" + + "\tagent_operation_type int4 DEFAULT 0,\n" + + "\tterminal_state int4 NULL DEFAULT 0,\n" + + "\treport_state int4 NULL DEFAULT 1,\n" + + "\tup_time varchar(64) NULL,\n" + + "\tboot_time timestamp(6) NULL,\n" + + "\ttenant varchar(2000) NOT NULL DEFAULT '',\n" + + "\tattr_destroy_time timestamp(6) DEFAULT NULL,\n" + + "\tattr_agent_id varchar(50) NOT NULL DEFAULT '',\n" + + " attr_app_type varchar(32) NOT NULL DEFAULT '',\n" + + " attr_parent_system varchar(64) NOT NULL DEFAULT '',\n" + + " attr_port varchar(2000) NOT NULL DEFAULT '',\n" + + " amdb_update_time timestamp(6) DEFAULT NULL,\n" + + " attr_instance_type varchar(32) default '',\n" + + "\tCONSTRAINT t_m_resource_monitor_pkey_test2 PRIMARY KEY (id));"); + + System.out.format("Table created: %d\n", ret); + + ret = stmt.executeUpdate("CREATE INDEX attr_agent_id_index_test2 ON wss_test.t_m_resource_monitor_test2 USING btree (attr_agent_id);"); + ret = stmt.executeUpdate("CREATE INDEX is_model_index_test2 ON wss_test.t_m_resource_monitor_test2 USING btree (is_model);"); + ret = stmt.executeUpdate("CREATE INDEX model_id_index_test2 ON wss_test.t_m_resource_monitor_test2 USING btree (model_id);"); + ret = stmt.executeUpdate("CREATE INDEX model_name_index_test2 ON wss_test.t_m_resource_monitor_test2 USING btree (model_name);"); + ret = stmt.executeUpdate("CREATE INDEX monitor_groupid_targetid_indx_test2 ON wss_test.t_m_resource_monitor_test2 USING btree (group_id);"); + + System.out.format("Indexes created: %d\n", ret); + + for (int i = 1; i <= 777; i++) { + ret = stmt.executeUpdate("insert into wss_test.t_m_resource_monitor_test2\n" + + "\t(id,\n" + + " name,\n" + + " resource_name,\n" + + " model_id,\n" + + " model_name,\n" + + " is_model,\n" + + " group_id,\n" + + " group_name,\n" + + " conf_group,\n" + + " logo_id,\n" + + " image_base64,\n" + + " ip,\n" + + " ipv6,\n" + + " full_ipv6,\n" + + " target_ip,\n" + + " state,\n" + + " amdb_state,\n" + + " monitor_item,\n" + + " gather_strategy,\n" + + " alarm_strategy,\n" + + " tenant,\n" + + " attr_destroy_time,\n" + + " attr_agent_id,\n" + + " attr_app_type,\n" + + " attr_parent_system,\n" + + " attr_port,\n" + + " amdb_update_time,\n" + + " modify_time,\n" + + " create_time,\n" + + " appchecker_state,\n" + + " attr_instance_type) \n" + + "\tvalues\n" + + "\t('6a0813c6-b4d4-4b9a-b2d6-diff" + i + "',\n" + + " '容器_apisix_docker://314b4850be647d3e1342f6aaf643e0b0742d5a0e8a5dd2c902f20a1a6a1c8dfe',\n" + + " 'apisix',\n" + + " '176f7ae1-65eb-4626-82bc-diff" + i + "',\n" + + " '容器',\n" + + " " + i + ",\n" + + " '0bdbae71-9546-4513-988b-diff" + i + "',\n" + + " 'Kubernetes',\n" + + " '默认配置组',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " 1,\n" + + " '下线',\n" + + " 0,\n" + + " 0,\n" + + " 0,\n" + + " '平台运营租户',\n" + + " '2023-06-30 19:59:10',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " '2023-06-30 19:59:14',\n" + + " '2023-06-30 20:05:00.292',\n" + + " '2023-06-30 19:59:14',\n" + + " 0,\n" + + " ' ');"); + } + + System.out.format("Data loaded: %d\n", ret); + + ret = stmt.executeUpdate("insert into wss_test.t_m_resource_monitor_test2\n" + + "\t(id,\n" + + " name,\n" + + " resource_name,\n" + + " model_id,\n" + + " model_name,\n" + + " is_model,\n" + + " group_id,\n" + + " group_name,\n" + + " conf_group,\n" + + " logo_id,\n" + + " image_base64,\n" + + " ip,\n" + + " ipv6,\n" + + " full_ipv6,\n" + + " target_ip,\n" + + " state,\n" + + " amdb_state,\n" + + " monitor_item,\n" + + " gather_strategy,\n" + + " alarm_strategy,\n" + + " tenant,\n" + + " attr_destroy_time,\n" + + " attr_agent_id,\n" + + " attr_app_type,\n" + + " attr_parent_system,\n" + + " attr_port,\n" + + " amdb_update_time,\n" + + " modify_time,\n" + + " create_time,\n" + + " appchecker_state,\n" + + " attr_instance_type) \n" + + "\tvalues\n" + + "\t('6a0813c6-b4d4-4b9a-b2d6-5f3c1d23a646',\n" + + " '容器_apisix_docker://314b4850be647d3e1342f6aaf643e0b0742d5a0e8a5dd2c902f20a1a6a1c8dfe',\n" + + " 'apisix',\n" + + " '176f7ae1-65eb-4626-82bc-687c1cd112d1',\n" + + " '容器',\n" + + " 0,\n" + + " '0bdbae71-9546-4513-988b-d1d2f920065c',\n" + + " 'Kubernetes',\n" + + " '默认配置组',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " 1,\n" + + " '下线',\n" + + " 0,\n" + + " 0,\n" + + " 0,\n" + + " '平台运营租户',\n" + + " '2023-06-30 19:59:10',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " '2023-06-30 19:59:14',\n" + + " '2023-06-30 20:05:00.292',\n" + + " '2023-06-30 19:59:14',\n" + + " 0,\n" + + " ' ')\n" + + "\tON DUPLICATE KEY UPDATE\n" + + "\t name = '容器_apisix_docker://314b4850be647d3e1342f6aaf643e0b0742d5a0e8a5dd2c902f20a1a6a1c8dfe',\n" + + "\t resource_name = 'apisix',\n" + + "\t model_id = '176f7ae1-65eb-4626-82bc-687c1cd112d1',\n" + + "\t model_name = '容器',\n" + + "\t is_model = 0,\n" + + "\t group_id = '0bdbae71-9546-4513-988b-d1d2f920065c',\n" + + "\t group_name = 'Kubernetes',\n" + + "\t conf_group = '默认配置组',\n" + + "\t logo_id = ' ',\n" + + "\t image_base64 = ' ',\n" + + "\t ip = ' ',\n" + + "\t ipv6 = ' ',\n" + + "\t full_ipv6 = ' ',\n" + + "\t target_ip = ' ',\n" + + "\t amdb_state = '下线',\n" + + "\t tenant = '平台运营租户',\n" + + "\t attr_destroy_time = '2023-06-30 19:59:10',\n" + + "\t attr_agent_id = ' ',\n" + + "\t attr_app_type = ' ',\n" + + "\t attr_parent_system = ' ',\n" + + "\t attr_port = ' ',\n" + + "\t amdb_update_time = '2023-06-30 19:59:14',\n" + + "\t modify_time = '2023-06-30 20:05:00.292',\n" + + "\t modifier = 'wss_insert',\n" + + "\t appchecker_state = 0,\n" + + "\t attr_instance_type = ' ';"); + + System.out.format("Row inserted: %d\n", ret); + + ResultSet rs = stmt.executeQuery("select count(*) from wss_test.t_m_resource_monitor_test2"); + while (rs.next()) { + System.out.format("Row count: %d\n", rs.getInt(1)); + } + + rs.close(); + stmt.close(); + } catch (SQLException e) { + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException e1) { + e1.printStackTrace(); + } + } + e.printStackTrace(); + } + } + + public static void main(String[] args) { + //创建数据库连接。 + Connection conn = GetConnection("testusr", "Test@123"); + //查询表。 + QueryTable(conn); + //关闭数据库连接。 + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/app/zh/blogs/wangshanshan/files/update_diff.java b/app/zh/blogs/wangshanshan/files/update_diff.java new file mode 100644 index 0000000000000000000000000000000000000000..8a20cb665fd0fa1c27c5c7353b3670307f316687 --- /dev/null +++ b/app/zh/blogs/wangshanshan/files/update_diff.java @@ -0,0 +1,178 @@ +//update.java +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.ResultSet; +import java.io.*; + +public class update_dup { + + //创建数据库连接。 + public static Connection GetConnection(String username, String passwd) { + String driver = "org.postgresql.Driver"; + String sourceURL = "jdbc:postgresql://127.0.0.1:5432/testdb"; + Connection conn = null; + try { + //加载数据库驱动。 + Class.forName(driver).newInstance(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + try { + //创建数据库连接。 + conn = DriverManager.getConnection(sourceURL, username, passwd); + System.out.println("Connection succeed!"); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + return conn; + } + + //执行普通SQL语句,查询测试表。 + public static void QueryTable(Connection conn) { + Statement stmt = null; + try { + stmt = conn.createStatement(); + //执行普通SQL语句。 + stmt.setFetchSize(50); + + int ret = 0; + + for (int i = 1; i <= 777; i++){ + ret = stmt.executeUpdate("insert into wss_test.t_m_resource_monitor_test2\n" + + "\t(id,\n" + + " name,\n" + + " resource_name,\n" + + " model_id,\n" + + " model_name,\n" + + " is_model,\n" + + " group_id,\n" + + " group_name,\n" + + " conf_group,\n" + + " logo_id,\n" + + " image_base64,\n" + + " ip,\n" + + " ipv6,\n" + + " full_ipv6,\n" + + " target_ip,\n" + + " state,\n" + + " amdb_state,\n" + + " monitor_item,\n" + + " gather_strategy,\n" + + " alarm_strategy,\n" + + " tenant,\n" + + " attr_destroy_time,\n" + + " attr_agent_id,\n" + + " attr_app_type,\n" + + " attr_parent_system,\n" + + " attr_port,\n" + + " amdb_update_time,\n" + + " modify_time,\n" + + " create_time,\n" + + " appchecker_state,\n" + + " attr_instance_type) \n" + + "\tvalues\n" + + "\t('6a0813c6-b4d4-4b9a-b2d6-5f3c1d23a646',\n" + + " '容器_apisix_docker://314b4850be647d3e1342f6aaf643e0b0742d5a0e8a5dd2c902f20a1a6a1c8dfe',\n" + + " 'apisix',\n" + + " '176f7ae1-65eb-4626-82bc-687c1cd112d1',\n" + + " '容器',\n" + + " 0,\n" + + " '0bdbae71-9546-4513-988b-d1d2f920065c',\n" + + " 'Kubernetes',\n" + + " '默认配置组',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " 1,\n" + + " '下线',\n" + + " 0,\n" + + " 0,\n" + + " 0,\n" + + " '平台运营租户',\n" + + " '2023-06-30 19:59:10',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " '2023-06-30 19:59:14',\n" + + " '2023-06-30 20:05:00.292',\n" + + " '2023-06-30 19:59:14',\n" + + " 0,\n" + + " ' ')\n" + + "\tON DUPLICATE KEY UPDATE\n" + + "\t name = '容器_apisix_docker://314b4850be647d3e1342f6aaf643e0b0742d5a0e8a5dd2c902f20a1a6a1c8dfe',\n" + + "\t resource_name = 'apisix',\n" + + "\t model_id = '176f7ae1-65eb-4626-82bc-diff" + i + "',\n" + + "\t model_name = '容器-diff" + i + "',\n" + + "\t is_model = " + i + ",\n" + + "\t group_id = '0bdbae71-9546-4513-988b-diff" + i + "',\n" + + "\t group_name = 'Kubernetes',\n" + + "\t conf_group = '默认配置组',\n" + + "\t logo_id = ' ',\n" + + "\t image_base64 = ' ',\n" + + "\t ip = ' ',\n" + + "\t ipv6 = ' ',\n" + + "\t full_ipv6 = ' ',\n" + + "\t target_ip = ' ',\n" + + "\t amdb_state = '下线',\n" + + "\t tenant = '平台运营租户',\n" + + "\t attr_destroy_time = '2023-06-30 19:59:10',\n" + + "\t attr_agent_id = 'diff-" + i + "',\n" + + "\t attr_app_type = ' ',\n" + + "\t attr_parent_system = ' ',\n" + + "\t attr_port = ' ',\n" + + "\t amdb_update_time = '2023-06-30 19:59:14',\n" + + "\t modify_time = '2023-06-30 20:05:00.292',\n" + + "\t modifier = 'wss_update-diff" + i + "',\n" + + "\t appchecker_state = 0,\n" + + "\t attr_instance_type = ' ';"); + + ResultSet rs = stmt.executeQuery("select xmin, xmax, modifier from wss_test.t_m_resource_monitor_test2 where id = '6a0813c6-b4d4-4b9a-b2d6-5f3c1d23a646'"); + while (rs.next()) + { + System.out.format("xmin=%d, xmax=%d, modifier=%s\n", rs.getInt(1), rs.getInt(2), rs.getString(3)); + } + } + + System.out.format("Row updated with diff: %d\n", ret); + + ResultSet rs = stmt.executeQuery("select count(*) from wss_test.t_m_resource_monitor_test2"); + while (rs.next()) + { + System.out.format("Row count: %d\n", rs.getInt(1)); + } + + rs.close(); + stmt.close(); + } catch (SQLException e) { + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException e1) { + e1.printStackTrace(); + } + } + e.printStackTrace(); + } + } + + public static void main(String[] args) { + //创建数据库连接。 + Connection conn = GetConnection("testusr", "Test@123"); + //查询表。 + QueryTable(conn); + //关闭数据库连接。 + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/app/zh/blogs/wangshanshan/files/update_dup.java b/app/zh/blogs/wangshanshan/files/update_dup.java new file mode 100644 index 0000000000000000000000000000000000000000..f875d87fa5963415cd4cc42825e1c4673dd89a02 --- /dev/null +++ b/app/zh/blogs/wangshanshan/files/update_dup.java @@ -0,0 +1,178 @@ +//update.java +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.ResultSet; +import java.io.*; + +public class update_dup { + + //创建数据库连接。 + public static Connection GetConnection(String username, String passwd) { + String driver = "org.postgresql.Driver"; + String sourceURL = "jdbc:postgresql://127.0.0.1:5432/testdb"; + Connection conn = null; + try { + //加载数据库驱动。 + Class.forName(driver).newInstance(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + try { + //创建数据库连接。 + conn = DriverManager.getConnection(sourceURL, username, passwd); + System.out.println("Connection succeed!"); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + return conn; + } + + //执行普通SQL语句,查询测试表。 + public static void QueryTable(Connection conn) { + Statement stmt = null; + try { + stmt = conn.createStatement(); + //执行普通SQL语句。 + stmt.setFetchSize(50); + + int ret = 0; + + for (int i = 1; i <= 777; i++){ + ret = stmt.executeUpdate("insert into wss_test.t_m_resource_monitor_test2\n" + + "\t(id,\n" + + " name,\n" + + " resource_name,\n" + + " model_id,\n" + + " model_name,\n" + + " is_model,\n" + + " group_id,\n" + + " group_name,\n" + + " conf_group,\n" + + " logo_id,\n" + + " image_base64,\n" + + " ip,\n" + + " ipv6,\n" + + " full_ipv6,\n" + + " target_ip,\n" + + " state,\n" + + " amdb_state,\n" + + " monitor_item,\n" + + " gather_strategy,\n" + + " alarm_strategy,\n" + + " tenant,\n" + + " attr_destroy_time,\n" + + " attr_agent_id,\n" + + " attr_app_type,\n" + + " attr_parent_system,\n" + + " attr_port,\n" + + " amdb_update_time,\n" + + " modify_time,\n" + + " create_time,\n" + + " appchecker_state,\n" + + " attr_instance_type) \n" + + "\tvalues\n" + + "\t('6a0813c6-b4d4-4b9a-b2d6-5f3c1d23a646',\n" + + " '容器_apisix_docker://314b4850be647d3e1342f6aaf643e0b0742d5a0e8a5dd2c902f20a1a6a1c8dfe',\n" + + " 'apisix',\n" + + " '176f7ae1-65eb-4626-82bc-687c1cd112d1',\n" + + " '容器',\n" + + " 0,\n" + + " '0bdbae71-9546-4513-988b-d1d2f920065c',\n" + + " 'Kubernetes',\n" + + " '默认配置组',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " 1,\n" + + " '下线',\n" + + " 0,\n" + + " 0,\n" + + " 0,\n" + + " '平台运营租户',\n" + + " '2023-06-30 19:59:10',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " ' ',\n" + + " '2023-06-30 19:59:14',\n" + + " '2023-06-30 20:05:00.292',\n" + + " '2023-06-30 19:59:14',\n" + + " 0,\n" + + " ' ')\n" + + "\tON DUPLICATE KEY UPDATE\n" + + "\t name = '容器_apisix_docker://314b4850be647d3e1342f6aaf643e0b0742d5a0e8a5dd2c902f20a1a6a1c8dfe',\n" + + "\t resource_name = 'apisix',\n" + + "\t model_id = '176f7ae1-65eb-4626-82bc-687c1cd112d1',\n" + + "\t model_name = '容器',\n" + + "\t is_model = 0,\n" + + "\t group_id = '0bdbae71-9546-4513-988b-d1d2f920065c',\n" + + "\t group_name = 'Kubernetes',\n" + + "\t conf_group = '默认配置组',\n" + + "\t logo_id = ' ',\n" + + "\t image_base64 = ' ',\n" + + "\t ip = ' ',\n" + + "\t ipv6 = ' ',\n" + + "\t full_ipv6 = ' ',\n" + + "\t target_ip = ' ',\n" + + "\t amdb_state = '下线',\n" + + "\t tenant = '平台运营租户',\n" + + "\t attr_destroy_time = '2023-06-30 19:59:10',\n" + + "\t attr_agent_id = ' ',\n" + + "\t attr_app_type = ' ',\n" + + "\t attr_parent_system = ' ',\n" + + "\t attr_port = ' ',\n" + + "\t amdb_update_time = '2023-06-30 19:59:14',\n" + + "\t modify_time = '2023-06-30 20:05:00.292',\n" + + "\t modifier = 'wss_update-dup" + i + "',\n" + + "\t appchecker_state = 0,\n" + + "\t attr_instance_type = ' ';"); + + ResultSet rs = stmt.executeQuery("select xmin, xmax, modifier from wss_test.t_m_resource_monitor_test2 where id = '6a0813c6-b4d4-4b9a-b2d6-5f3c1d23a646'"); + while (rs.next()) + { + System.out.format("xmin=%d, xmax=%d, modifier=%s\n", rs.getInt(1), rs.getInt(2), rs.getString(3)); + } + } + + System.out.format("Row updated with dup: %d\n", ret); + + ResultSet rs = stmt.executeQuery("select count(*) from wss_test.t_m_resource_monitor_test2"); + while (rs.next()) + { + System.out.format("Count: %d\n", rs.getInt(1)); + } + + rs.close(); + stmt.close(); + } catch (SQLException e) { + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException e1) { + e1.printStackTrace(); + } + } + e.printStackTrace(); + } + } + + public static void main(String[] args) { + //创建数据库连接。 + Connection conn = GetConnection("testusr", "Test@123"); + //查询表。 + QueryTable(conn); + //关闭数据库连接。 + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/app/zh/blogs/wangshanshan/images/img.png b/app/zh/blogs/wangshanshan/images/img.png new file mode 100644 index 0000000000000000000000000000000000000000..64519c51468b2d7de5f8cc9386b30edf5c1cc834 Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img.png differ diff --git a/app/zh/blogs/wangshanshan/images/img_1.png b/app/zh/blogs/wangshanshan/images/img_1.png new file mode 100644 index 0000000000000000000000000000000000000000..c353b690ccc36dbbe2ab4a966d81dfaa25a819b8 Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img_1.png differ diff --git a/app/zh/blogs/wangshanshan/images/img_10.png b/app/zh/blogs/wangshanshan/images/img_10.png new file mode 100644 index 0000000000000000000000000000000000000000..932428614110b0e2965ce3ac757f9631d13138d9 Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img_10.png differ diff --git a/app/zh/blogs/wangshanshan/images/img_12.png b/app/zh/blogs/wangshanshan/images/img_12.png new file mode 100644 index 0000000000000000000000000000000000000000..046a732f710e7c933dbf187b22657f42af059fd0 Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img_12.png differ diff --git a/app/zh/blogs/wangshanshan/images/img_2.png b/app/zh/blogs/wangshanshan/images/img_2.png new file mode 100644 index 0000000000000000000000000000000000000000..fe06b664108370f0c6e1f57b6a5432fddcedc6f9 Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img_2.png differ diff --git a/app/zh/blogs/wangshanshan/images/img_3.png b/app/zh/blogs/wangshanshan/images/img_3.png new file mode 100644 index 0000000000000000000000000000000000000000..25878787c742ae80700e34e625220ffbd94f5829 Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img_3.png differ diff --git a/app/zh/blogs/wangshanshan/images/img_4.png b/app/zh/blogs/wangshanshan/images/img_4.png new file mode 100644 index 0000000000000000000000000000000000000000..a7953bfb1e69514b162cccc7df2b99874002ac6f Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img_4.png differ diff --git a/app/zh/blogs/wangshanshan/images/img_5.png b/app/zh/blogs/wangshanshan/images/img_5.png new file mode 100644 index 0000000000000000000000000000000000000000..6ffeac53cfd9acc1db1ea6317b6911def2158cad Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img_5.png differ diff --git a/app/zh/blogs/wangshanshan/images/img_6.png b/app/zh/blogs/wangshanshan/images/img_6.png new file mode 100644 index 0000000000000000000000000000000000000000..372d405e93c13606d83a9c86a82240c6f6ad94da Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img_6.png differ diff --git a/app/zh/blogs/wangshanshan/images/img_7.png b/app/zh/blogs/wangshanshan/images/img_7.png new file mode 100644 index 0000000000000000000000000000000000000000..6f308efd287c162a03b792012059053879d06a03 Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img_7.png differ diff --git a/app/zh/blogs/wangshanshan/images/img_8.png b/app/zh/blogs/wangshanshan/images/img_8.png new file mode 100644 index 0000000000000000000000000000000000000000..ef4d8232ab8e0df55e25d16d3e96c3523499c5cc Binary files /dev/null and b/app/zh/blogs/wangshanshan/images/img_8.png differ