diff --git a/.codex-police-test-pom.xml b/.codex-police-test-pom.xml deleted file mode 100644 index decf7a0..0000000 --- a/.codex-police-test-pom.xml +++ /dev/null @@ -1,374 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.3.2 - - - com.biutag - supervision - 0.0.1-SNAPSHOT - supervision - 长沙公安数据督察 - - - - - - - - - - - - - - - 17 - - - - - org.jfree - jfreechart - 1.5.4 - - - - com.deepoove - poi-tl - 1.12.2 - - - org.apache.poi - poi - - - org.apache.poi - poi-ooxml - - - org.apache.poi - poi-ooxml-lite - - - - - - org.projectlombok - lombok - true - - - - - org.mapstruct - mapstruct - 1.5.5.Final - - - - - org.mapstruct - mapstruct-processor - 1.5.5.Final - provided - - - - - com.google.guava - guava - 32.1.2-jre - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-validation - - - - org.springframework.boot - spring-boot-starter-data-redis-reactive - - - - - - com.dameng - DmJdbcDriver18 - 8.1.3.140 - - - - - - - - - - - - com.mysql - mysql-connector-j - runtime - - - - - com.microsoft.sqlserver - mssql-jdbc - 12.8.1.jre11 - - - javax.xml.bind - jaxb-api - 2.3.0 - - - com.sun.xml.bind - jaxb-impl - 2.3.0 - - - com.sun.xml.bind - jaxb-core - 2.3.0 - - - javax.activation - activation - 1.1.1 - - - - - com.gbase - gbase-jdbc - system - 8.3.81.53-build55.2.1-bin - ${project.basedir}/src/main/resources/lib/gbase-connector-java-8.3.81.53-build52.8-bin.jar - - - - - com.dameng - DmJdbcDriver18 - 8.1.3.140 - - - - - org.postgresql - postgresql - 42.7.4 - - - - com.alibaba - druid-spring-boot-starter - 1.2.22 - - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - - com.baomidou - mybatis-plus-spring-boot3-starter - 3.5.7 - - - - com.alibaba - easyexcel - 4.0.1 - - - - commons-io - commons-io - 2.17.0 - - - - cn.hutool - hutool-all - 5.8.29 - - - - - cn.hutool - hutool-core - 5.8.29 - - - cn.hutool - hutool-http - 5.8.29 - - - - com.baomidou - dynamic-datasource-spring-boot3-starter - 4.3.1 - - - - org.freemarker - freemarker - 2.3.32 - - - - org.springframework.security - spring-security-crypto - - - - com.github.tobato - fastdfs-client - 1.27.2 - - - - - com.github.xiaoymin - knife4j-openapi3-jakarta-spring-boot-starter - 4.1.0 - - - - com.alibaba - fastjson - 2.0.53 - - - - net.logstash.logback - logstash-logback-encoder - 4.9 - - - - - com.aspose - aspose-words - 15.8.0 - - - org.springframework.boot - spring-boot-starter-actuator - - - - - cn.com.jit - authSDK - 3.0.3 - - - commons-httpclient - commons-httpclient - 3.0.1 - - - - org.jsoup - jsoup - 1.17.2 - - - - - - - - src/main/resources - false - - - - src/main/resources - - application.yml - - true - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.2.5 - - false - - - - org.springframework.boot - spring-boot-maven-plugin - - true - - - org.projectlombok - lombok - - - - - - - supervision - - - - - local - - - local - - - - - true - - - - dev - - - dev - - - - prod - - prod - - - - - diff --git a/pom.codex-query-verify.xml b/pom.codex-query-verify.xml deleted file mode 100644 index decf7a0..0000000 --- a/pom.codex-query-verify.xml +++ /dev/null @@ -1,374 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.3.2 - - - com.biutag - supervision - 0.0.1-SNAPSHOT - supervision - 长沙公安数据督察 - - - - - - - - - - - - - - - 17 - - - - - org.jfree - jfreechart - 1.5.4 - - - - com.deepoove - poi-tl - 1.12.2 - - - org.apache.poi - poi - - - org.apache.poi - poi-ooxml - - - org.apache.poi - poi-ooxml-lite - - - - - - org.projectlombok - lombok - true - - - - - org.mapstruct - mapstruct - 1.5.5.Final - - - - - org.mapstruct - mapstruct-processor - 1.5.5.Final - provided - - - - - com.google.guava - guava - 32.1.2-jre - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-validation - - - - org.springframework.boot - spring-boot-starter-data-redis-reactive - - - - - - com.dameng - DmJdbcDriver18 - 8.1.3.140 - - - - - - - - - - - - com.mysql - mysql-connector-j - runtime - - - - - com.microsoft.sqlserver - mssql-jdbc - 12.8.1.jre11 - - - javax.xml.bind - jaxb-api - 2.3.0 - - - com.sun.xml.bind - jaxb-impl - 2.3.0 - - - com.sun.xml.bind - jaxb-core - 2.3.0 - - - javax.activation - activation - 1.1.1 - - - - - com.gbase - gbase-jdbc - system - 8.3.81.53-build55.2.1-bin - ${project.basedir}/src/main/resources/lib/gbase-connector-java-8.3.81.53-build52.8-bin.jar - - - - - com.dameng - DmJdbcDriver18 - 8.1.3.140 - - - - - org.postgresql - postgresql - 42.7.4 - - - - com.alibaba - druid-spring-boot-starter - 1.2.22 - - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - - com.baomidou - mybatis-plus-spring-boot3-starter - 3.5.7 - - - - com.alibaba - easyexcel - 4.0.1 - - - - commons-io - commons-io - 2.17.0 - - - - cn.hutool - hutool-all - 5.8.29 - - - - - cn.hutool - hutool-core - 5.8.29 - - - cn.hutool - hutool-http - 5.8.29 - - - - com.baomidou - dynamic-datasource-spring-boot3-starter - 4.3.1 - - - - org.freemarker - freemarker - 2.3.32 - - - - org.springframework.security - spring-security-crypto - - - - com.github.tobato - fastdfs-client - 1.27.2 - - - - - com.github.xiaoymin - knife4j-openapi3-jakarta-spring-boot-starter - 4.1.0 - - - - com.alibaba - fastjson - 2.0.53 - - - - net.logstash.logback - logstash-logback-encoder - 4.9 - - - - - com.aspose - aspose-words - 15.8.0 - - - org.springframework.boot - spring-boot-starter-actuator - - - - - cn.com.jit - authSDK - 3.0.3 - - - commons-httpclient - commons-httpclient - 3.0.1 - - - - org.jsoup - jsoup - 1.17.2 - - - - - - - - src/main/resources - false - - - - src/main/resources - - application.yml - - true - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.2.5 - - false - - - - org.springframework.boot - spring-boot-maven-plugin - - true - - - org.projectlombok - lombok - - - - - - - supervision - - - - - local - - - local - - - - - true - - - - dev - - - dev - - - - prod - - prod - - - - - diff --git a/sql/20261027_profile_query_column_check.sql b/sql/20261027_profile_query_column_check.sql new file mode 100644 index 0000000..6f242be --- /dev/null +++ b/sql/20261027_profile_query_column_check.sql @@ -0,0 +1,43 @@ +-- MySQL 5.7.21:只读核查关联字段,不查询业务明细。 +-- 在 result.txt 对应的业务库执行,返回全部结果集。 +SELECT VERSION(), DATABASE(), @@character_set_connection, @@collation_connection; + +SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, + CHARACTER_SET_NAME, COLLATION_NAME, COLUMN_KEY +FROM information_schema.COLUMNS +WHERE TABLE_SCHEMA = DATABASE() + AND ( + (TABLE_NAME = 'negative' AND COLUMN_NAME IN ('id', 'involveDepartId', 'crtTime', 'discoveryTime', 'processing_status', 'checkStatus')) + OR (TABLE_NAME = 'negative_blame' AND COLUMN_NAME IN ('negativeId', 'blameIdCode', 'type')) + OR (TABLE_NAME = 'sup_depart' AND COLUMN_NAME IN ('id', 'pid')) + OR (TABLE_NAME = 'sup_depart_police_size' AND COLUMN_NAME = 'depart_id') + OR (TABLE_NAME = 'sup_police' AND COLUMN_NAME IN ('id_code', 'org_id', 'del')) + ) +ORDER BY TABLE_NAME, ORDINAL_POSITION; + +-- JSON 计划中的 attached_condition 可显示隐式转换,SHOW WARNINGS 紧随 EXPLAIN 执行。 +EXPLAIN FORMAT=JSON +SELECT n.id, nb.blameIdCode +FROM negative n +LEFT JOIN negative_blame nb ON nb.negativeId = n.id +WHERE n.crtTime BETWEEN '1949-01-01 00:00:00' AND NOW() +LIMIT 10; +SHOW WARNINGS; + +EXPLAIN FORMAT=JSON +SELECT d.id, p.police_size +FROM sup_depart d +LEFT JOIN sup_depart_police_size p ON p.depart_id = d.id +WHERE d.level = 3 +LIMIT 10; +SHOW WARNINGS; + +EXPLAIN FORMAT=JSON +SELECT d.id +FROM sup_depart d +WHERE d.level = 3 AND EXISTS ( + SELECT 1 FROM negative n + WHERE n.involveDepartId = d.id + AND n.crtTime BETWEEN '1949-01-01 00:00:00' AND NOW() +); +SHOW WARNINGS; diff --git a/sql/20261027_profile_query_explain.sql b/sql/20261027_profile_query_explain.sql index 344b40c..ac4f48a 100644 --- a/sql/20261027_profile_query_explain.sql +++ b/sql/20261027_profile_query_explain.sql @@ -31,12 +31,12 @@ SELECT LEFT JOIN negative_blame nb ON n.id = nb.negativeId WHERE d.level = 3 AND n.crtTime BETWEEN @beginTime AND @endTime - - - + + + GROUP BY d.id, d1.short_name, d.short_name, p.police_size, p.aux_size ORDER BY - verify_size + verify_size DESC , d.id ASC LIMIT 0, 10; @@ -58,9 +58,9 @@ SELECT LEFT JOIN negative_blame nb ON n.id = nb.negativeId WHERE d.level = 3 AND n.crtTime BETWEEN @beginTime AND @endTime - - - + + + GROUP BY d.id, d1.short_name, d.short_name, p.police_size, p.aux_size ) counted; @@ -79,22 +79,22 @@ SELECT DISTINCT count(DISTINCT nb.blameIdCode) verify_police_size, count(DISTINCT n.id) verify_size FROM sup_depart d - INNER JOIN negative n ON d.id = n.involveDepartId - LEFT JOIN negative_blame nb ON n.id = nb.negativeId - WHERE + INNER JOIN negative n ON n.involveDepartId = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci + LEFT JOIN negative_blame nb ON nb.negativeId = CONVERT(n.id USING utf8) COLLATE utf8_general_ci + WHERE d.level = 3 - - - - + + + + AND n.crtTime BETWEEN @beginTime AND @endTime GROUP BY d.id ) stats INNER JOIN sup_depart d ON d.id = stats.depart_id LEFT JOIN sup_depart d1 ON d.pid = d1.id - LEFT JOIN sup_depart_police_size p ON p.depart_id = d.id + LEFT JOIN sup_depart_police_size p ON p.depart_id = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci ORDER BY - verify_size + verify_size DESC , d.id ASC LIMIT 0, 10; @@ -103,16 +103,16 @@ EXPLAIN SELECT count(*) FROM ( SELECT DISTINCT d.id, p.police_size, p.aux_size FROM sup_depart d - LEFT JOIN sup_depart_police_size p ON p.depart_id = d.id - WHERE + LEFT JOIN sup_depart_police_size p ON p.depart_id = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci + WHERE d.level = 3 - - - - + + + + AND EXISTS ( SELECT 1 FROM negative n - WHERE n.involveDepartId = d.id + WHERE n.involveDepartId = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci AND n.crtTime BETWEEN @beginTime AND @endTime ) ) counted; @@ -141,11 +141,11 @@ SELECT AND n.checkStatus IN ('1', '2') AND n.processing_status = 'completed' AND n.discoveryTime BETWEEN @beginTime AND @endTime - - - - + + + + GROUP BY p.id_code, p.NAME, @@ -186,11 +186,11 @@ SELECT AND n.checkStatus IN ('1', '2') AND n.processing_status = 'completed' AND n.discoveryTime BETWEEN @beginTime AND @endTime - - - - + + + + GROUP BY p.id_code, p.NAME, @@ -205,7 +205,7 @@ SELECT -- 个人问题库:优化后列表查询(第一页 10 条) EXPLAIN -SELECT DISTINCT +SELECT DISTINCT p.id_code, p.name, p.emp_no, p.position, p.employment_date, p.person_type, d.short_name depart_name, d.id depart_id, d1.short_name parent_depart_name , stats.verify_size @@ -213,24 +213,24 @@ SELECT DISTINCT SELECT nb.blameIdCode, count(DISTINCT n.id) verify_size FROM negative n INNER JOIN negative_blame nb ON nb.negativeId = n.id - WHERE + WHERE nb.type = 'personal' AND n.checkStatus IN ('1', '2') AND n.processing_status = 'completed' AND n.discoveryTime BETWEEN @beginTime AND @endTime - + GROUP BY nb.blameIdCode ) stats INNER JOIN sup_police p ON p.id_code = stats.blameIdCode LEFT JOIN sup_depart d ON p.org_id = d.id LEFT JOIN sup_depart d1 ON d.pid = d1.id AND d1.level >= 2 - WHERE + WHERE p.del = 0 - - - - - + + + + + ORDER BY verify_size DESC , p.id_code ASC LIMIT 0, 10; @@ -238,30 +238,31 @@ LIMIT 0, 10; -- 个人问题库:优化后分页总数 EXPLAIN SELECT count(*) FROM ( - SELECT DISTINCT + SELECT DISTINCT p.id_code, p.name, p.emp_no, p.position, p.employment_date, p.person_type, d.short_name depart_name, d.id depart_id, d1.short_name parent_depart_name - + FROM sup_police p LEFT JOIN sup_depart d ON p.org_id = d.id LEFT JOIN sup_depart d1 ON d.pid = d1.id AND d1.level >= 2 - WHERE + WHERE p.del = 0 - - - - - + + + + + AND EXISTS ( SELECT 1 FROM negative_blame nb - INNER JOIN negative n ON nb.negativeId = n.id - WHERE nb.blameIdCode = p.id_code - AND - nb.type = 'personal' - AND n.checkStatus IN ('1', '2') + WHERE nb.blameIdCode = p.id_code AND nb.type = 'personal' + AND EXISTS ( + SELECT 1 FROM negative n + WHERE n.id = nb.negativeId + AND + n.checkStatus IN ('1', '2') AND n.processing_status = 'completed' AND n.discoveryTime BETWEEN @beginTime AND @endTime - + + ) ) ) counted; - diff --git a/sql/20261027_profile_query_indexes.sql b/sql/20261027_profile_query_indexes.sql index 106b831..c19689e 100644 --- a/sql/20261027_profile_query_indexes.sql +++ b/sql/20261027_profile_query_indexes.sql @@ -1,3 +1,5 @@ +-- 暂缓执行:生产 result.txt 显示已有连接索引未被用作查找,需先核对字段类型与字符集。 +-- 先执行 20261027_profile_query_column_check.sql,再根据结果修订本候选脚本。 -- 单位/个人问题库查询索引,MySQL InnoDB。 -- 在目标业务库执行;先核对字段类型、索引长度和剩余磁盘空间。 -- 按完整左前缀识别已有等价索引;LOCK=NONE 不支持时会报错,不自动降级为锁表。 @@ -12,7 +14,7 @@ SET @profile_index_sql = IF( WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'negative' AND INDEX_TYPE = 'BTREE' GROUP BY INDEX_NAME ) existing_indexes - WHERE prefix_parts = 0 AND (columns_in_index = 'involveDepartId,crtTime' OR columns_in_index LIKE 'involveDepartId,crtTime,%') + WHERE prefix_parts = 0 AND (columns_in_index = 'involveDepartId,crtTime' OR LEFT(columns_in_index, LENGTH('involveDepartId,crtTime') + 1) = CONCAT('involveDepartId,crtTime', ',')) ), 'SELECT ''idx_profile_depart_time: existing equivalent index, skipped'' AS result', 'ALTER TABLE `negative` ADD INDEX `idx_profile_depart_time` (`involveDepartId`, `crtTime`), ALGORITHM=INPLACE, LOCK=NONE' @@ -30,7 +32,7 @@ SET @profile_index_sql = IF( WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'negative' AND INDEX_TYPE = 'BTREE' GROUP BY INDEX_NAME ) existing_indexes - WHERE prefix_parts = 0 AND (columns_in_index = 'processing_status,checkStatus,discoveryTime' OR columns_in_index LIKE 'processing_status,checkStatus,discoveryTime,%') + WHERE prefix_parts = 0 AND (columns_in_index = 'processing_status,checkStatus,discoveryTime' OR LEFT(columns_in_index, LENGTH('processing_status,checkStatus,discoveryTime') + 1) = CONCAT('processing_status,checkStatus,discoveryTime', ',')) ), 'SELECT ''idx_profile_verified_time: existing equivalent index, skipped'' AS result', 'ALTER TABLE `negative` ADD INDEX `idx_profile_verified_time` (`processing_status`, `checkStatus`, `discoveryTime`), ALGORITHM=INPLACE, LOCK=NONE' @@ -48,7 +50,7 @@ SET @profile_index_sql = IF( WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'negative_blame' AND INDEX_TYPE = 'BTREE' GROUP BY INDEX_NAME ) existing_indexes - WHERE prefix_parts = 0 AND (columns_in_index = 'negativeId,type,blameIdCode' OR columns_in_index LIKE 'negativeId,type,blameIdCode,%') + WHERE prefix_parts = 0 AND (columns_in_index = 'negativeId,type,blameIdCode' OR LEFT(columns_in_index, LENGTH('negativeId,type,blameIdCode') + 1) = CONCAT('negativeId,type,blameIdCode', ',')) ), 'SELECT ''idx_profile_problem_person: existing equivalent index, skipped'' AS result', 'ALTER TABLE `negative_blame` ADD INDEX `idx_profile_problem_person` (`negativeId`, `type`, `blameIdCode`), ALGORITHM=INPLACE, LOCK=NONE' @@ -66,7 +68,7 @@ SET @profile_index_sql = IF( WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'negative_blame' AND INDEX_TYPE = 'BTREE' GROUP BY INDEX_NAME ) existing_indexes - WHERE prefix_parts = 0 AND (columns_in_index = 'blameIdCode,type,negativeId' OR columns_in_index LIKE 'blameIdCode,type,negativeId,%') + WHERE prefix_parts = 0 AND (columns_in_index = 'blameIdCode,type,negativeId' OR LEFT(columns_in_index, LENGTH('blameIdCode,type,negativeId') + 1) = CONCAT('blameIdCode,type,negativeId', ',')) ), 'SELECT ''idx_profile_person_problem: existing equivalent index, skipped'' AS result', 'ALTER TABLE `negative_blame` ADD INDEX `idx_profile_person_problem` (`blameIdCode`, `type`, `negativeId`), ALGORITHM=INPLACE, LOCK=NONE' @@ -84,7 +86,7 @@ SET @profile_index_sql = IF( WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sup_police' AND INDEX_TYPE = 'BTREE' GROUP BY INDEX_NAME ) existing_indexes - WHERE prefix_parts = 0 AND (columns_in_index = 'id_code,del' OR columns_in_index LIKE 'id_code,del,%') + WHERE prefix_parts = 0 AND (columns_in_index = 'id_code,del' OR LEFT(columns_in_index, LENGTH('id_code,del') + 1) = CONCAT('id_code,del', ',')) ), 'SELECT ''idx_profile_police_identity: existing equivalent index, skipped'' AS result', 'ALTER TABLE `sup_police` ADD INDEX `idx_profile_police_identity` (`id_code`, `del`), ALGORITHM=INPLACE, LOCK=NONE' diff --git a/sql/20261027_profile_query_performance.md b/sql/20261027_profile_query_performance.md index 7adc03d..e1d9354 100644 --- a/sql/20261027_profile_query_performance.md +++ b/sql/20261027_profile_query_performance.md @@ -21,3 +21,38 @@ - 本地模拟使用 SQLite 内存数据库及 12 万条问题,属于结果一致性和优化方向验证,不是生产 MySQL 5.7 性能验收。 - 开发数据库连接失败;生产索引、执行计划和端到端耗时尚未取得,不能承诺已达到 3 秒。 - 索引脚本尚未对任何数据库执行;本次未改前端或运行前端构建。 + +## 本地模拟记录 + +数据:12 万条问题、约 43.6 万条责任记录、1.2 万个人、200 个三级单位,包含重复人员资料、重复责任记录、空身份证号和不符合状态/时间条件的记录。使用 SQLite 内存数据库及拟新增索引;新旧查询在相同索引下比较。 + +两类列表各 10 组筛选/排序场景的全部返回行、总数和第二页条数一致。每次计时包含分页总数查询及第一页 10 条列表查询,取三次中位数: + +| 查询 | 原查询 | 优化后 | +| --- | ---: | ---: | +| 单位问题库 | 9435.6 ms | 2198.2 ms | +| 个人问题库 | 3227.7 ms | 1009.9 ms | + +这些数字仅用于本地优化方向验证;不含生产网络、真实字段宽度/索引分布、磁盘和并发开销,不能据此认定生产接口已达到 3 秒。 + +## 生产执行计划反馈(2026-10-27) + +result.txt 的表规模为 information_schema 估计:negative 112186 行、negative_blame 117768 行、sup_police 21144 行。 + +- 单位原查询和改写后的聚合查询中,negative_blame 都未出现可用的连接索引(possible_keys 为空),扫描 idx_negativeId_blameIdCode 全索引并使用 Block Nested Loop。该索引明明以 negativeId 开头,需优先检查其与 negative.id 的数据类型、字符集和排序规则。 +- 单位人数表 sup_depart_police_size 有 depart_id 主键,却以 ALL + Block Nested Loop 关联;sup_depart.id 的主键 key_len 为 4,需检查两侧类型是否一致。 +- 单位分页总数的 DEPENDENT SUBQUERY 估计扫描 negative 112186 条索引记录;需检查 negative.involveDepartId 与 sup_depart.id 的类型转换。 +- 个人优化后列表中 sup_police 已使用 index_id_code 的 ref 查找,negative 使用主键 eq_ref;这是计划改善,但尚无实测耗时。其 ref=func 表明关联表达式经过计算,需通过 JSON 计划确认具体转换。 +- 上述推导出的万亿级派生表 rows 是优化器估计,不是实际生成或扫描的行数。 + +下一步执行 20261027_profile_query_column_check.sql。现有候选索引脚本暂缓执行;在明确字段定义前不添加 CAST、CONVERT、FORCE INDEX,也不直接修改生产字段,避免统计语义变化或无效建索引。 + +## 已确认的索引失效原因及修正(result1.txt) + +- negative.id 为 utf8mb4,negative_blame.negativeId 为 utf8。原执行计划在 nb.negativeId 上执行 CONVERT(... USING utf8mb4),导致责任表全索引扫描。单位列表改为在驱动侧 n.id 转成 utf8,并显式指定 utf8_general_ci,让 nb.negativeId 保持原始索引列。 +- sup_depart.id 为 int,negative.involveDepartId 和 sup_depart_police_size.depart_id 为 utf8 varchar。MySQL 返回 Warning 1739,无法对这两个字符串索引做 ref/range 查找。列表和总数查询改为将 d.id 转成 utf8 字符串,不对被查找的字符串列做函数转换。 +- 个人列表中 n 主键原本已为 eq_ref,不盲目反转该关联的转换方向。继续保留先聚合后关联的优化,通过生产复测决定是否需要覆盖索引。 + +执行 20261027_profile_query_retest.sql:先单独执行数据检查,三项 affected_rows 全为 0 才部署单位查询;非零说明前导零/非标准数字或不能转换为 utf8 的问题 ID 可能影响新旧统计一致性,必须先核查。后续 SQL 提供新计划和 SQL_NO_CACHE 实测,SHOW PROFILES 中列表与总数的 Duration 之和才是该页的数据库耗时;接口还包含网络与应用开销。 + +本次未执行生产 DDL;候选索引仍暂缓,优先复用已有索引验证转换方向修正的收益。生产 3 秒目标尚未验收。 diff --git a/sql/20261027_profile_query_retest.sql b/sql/20261027_profile_query_retest.sql new file mode 100644 index 0000000..e4cdac8 --- /dev/null +++ b/sql/20261027_profile_query_retest.sql @@ -0,0 +1,256 @@ +-- MySQL 5.7.21:result1.txt 确认类型/字符集不一致后的复测,无 DDL、无业务数据修改。 +-- 步骤一:先单独执行以下检查。affected_rows 必须全部为 0,才部署新版单位查询。 +-- 非零时请返回计数,先处理编号语义差异,不要直接部署。 +SELECT 'negative.involveDepartId 非标准编号' AS check_item, COUNT(*) AS affected_rows +FROM negative n JOIN sup_depart d ON n.involveDepartId = d.id +WHERE d.level = 3 + AND NOT (n.involveDepartId = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci) +UNION ALL +SELECT 'sup_depart_police_size.depart_id 非标准编号', COUNT(*) +FROM sup_depart_police_size p JOIN sup_depart d ON p.depart_id = d.id +WHERE d.level = 3 + AND NOT (p.depart_id = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci) +UNION ALL +SELECT 'negative.id 无法无损转成 utf8', COUNT(*) +FROM negative +WHERE BINARY id <> BINARY CONVERT(CONVERT(id USING utf8) USING utf8mb4); + +-- 步骤二:以上计数全为 0 后,执行下列 EXPLAIN 和实际查询。 +-- 预期:nb 不再全索引扫描+Block Nested Loop,p 使用主键,单位总数中的 n 使用单位索引。 +-- 查询时间仍需实测;请返回四份 EXPLAIN 和 SHOW PROFILES 的耗时,无需返回人员明细。 +SET @beginTime = '1949-01-01 00:00:00'; +SET @endTime = NOW(); +SET profiling = 1; + +-- 单位问题库:优化后列表查询(第一页 10 条) +EXPLAIN +SELECT DISTINCT + d.id depart_id, + d1.short_name parent_depart_name, + d.short_name depart_name, + p.police_size, + p.aux_size, + stats.verify_police_size, + stats.verify_size + FROM ( + SELECT d.id depart_id, + count(DISTINCT nb.blameIdCode) verify_police_size, + count(DISTINCT n.id) verify_size + FROM sup_depart d + INNER JOIN negative n ON n.involveDepartId = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci + LEFT JOIN negative_blame nb ON nb.negativeId = CONVERT(n.id USING utf8) COLLATE utf8_general_ci + WHERE + d.level = 3 + + + + + AND n.crtTime BETWEEN @beginTime AND @endTime + GROUP BY d.id + ) stats + INNER JOIN sup_depart d ON d.id = stats.depart_id + LEFT JOIN sup_depart d1 ON d.pid = d1.id + LEFT JOIN sup_depart_police_size p ON p.depart_id = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci + ORDER BY + verify_size + DESC , d.id ASC +LIMIT 0, 10; +SHOW WARNINGS; + +SELECT SQL_NO_CACHE DISTINCT + d.id depart_id, + d1.short_name parent_depart_name, + d.short_name depart_name, + p.police_size, + p.aux_size, + stats.verify_police_size, + stats.verify_size + FROM ( + SELECT d.id depart_id, + count(DISTINCT nb.blameIdCode) verify_police_size, + count(DISTINCT n.id) verify_size + FROM sup_depart d + INNER JOIN negative n ON n.involveDepartId = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci + LEFT JOIN negative_blame nb ON nb.negativeId = CONVERT(n.id USING utf8) COLLATE utf8_general_ci + WHERE + d.level = 3 + + + + + AND n.crtTime BETWEEN @beginTime AND @endTime + GROUP BY d.id + ) stats + INNER JOIN sup_depart d ON d.id = stats.depart_id + LEFT JOIN sup_depart d1 ON d.pid = d1.id + LEFT JOIN sup_depart_police_size p ON p.depart_id = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci + ORDER BY + verify_size + DESC , d.id ASC +LIMIT 0, 10; + +-- 单位问题库:优化后分页总数 +EXPLAIN +SELECT count(*) FROM ( + SELECT DISTINCT d.id, p.police_size, p.aux_size + FROM sup_depart d + LEFT JOIN sup_depart_police_size p ON p.depart_id = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci + WHERE + d.level = 3 + + + + + AND EXISTS ( + SELECT 1 FROM negative n + WHERE n.involveDepartId = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci + AND n.crtTime BETWEEN @beginTime AND @endTime + ) + ) counted; +SHOW WARNINGS; + +SELECT SQL_NO_CACHE count(*) FROM ( + SELECT DISTINCT d.id, p.police_size, p.aux_size + FROM sup_depart d + LEFT JOIN sup_depart_police_size p ON p.depart_id = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci + WHERE + d.level = 3 + + + + + AND EXISTS ( + SELECT 1 FROM negative n + WHERE n.involveDepartId = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci + AND n.crtTime BETWEEN @beginTime AND @endTime + ) + ) counted; + +-- 个人问题库:优化后列表查询(第一页 10 条) +EXPLAIN +SELECT DISTINCT + p.id_code, p.name, p.emp_no, p.position, p.employment_date, p.person_type, + d.short_name depart_name, d.id depart_id, d1.short_name parent_depart_name + , stats.verify_size + FROM ( + SELECT nb.blameIdCode, count(DISTINCT n.id) verify_size + FROM negative n + INNER JOIN negative_blame nb ON nb.negativeId = n.id + WHERE + nb.type = 'personal' + AND n.checkStatus IN ('1', '2') + AND n.processing_status = 'completed' + AND n.discoveryTime BETWEEN @beginTime AND @endTime + + GROUP BY nb.blameIdCode + ) stats + INNER JOIN sup_police p ON p.id_code = stats.blameIdCode + LEFT JOIN sup_depart d ON p.org_id = d.id + LEFT JOIN sup_depart d1 ON d.pid = d1.id AND d1.level >= 2 + WHERE + p.del = 0 + + + + + + ORDER BY verify_size + DESC , p.id_code ASC +LIMIT 0, 10; +SHOW WARNINGS; + +SELECT SQL_NO_CACHE DISTINCT + p.id_code, p.name, p.emp_no, p.position, p.employment_date, p.person_type, + d.short_name depart_name, d.id depart_id, d1.short_name parent_depart_name + , stats.verify_size + FROM ( + SELECT nb.blameIdCode, count(DISTINCT n.id) verify_size + FROM negative n + INNER JOIN negative_blame nb ON nb.negativeId = n.id + WHERE + nb.type = 'personal' + AND n.checkStatus IN ('1', '2') + AND n.processing_status = 'completed' + AND n.discoveryTime BETWEEN @beginTime AND @endTime + + GROUP BY nb.blameIdCode + ) stats + INNER JOIN sup_police p ON p.id_code = stats.blameIdCode + LEFT JOIN sup_depart d ON p.org_id = d.id + LEFT JOIN sup_depart d1 ON d.pid = d1.id AND d1.level >= 2 + WHERE + p.del = 0 + + + + + + ORDER BY verify_size + DESC , p.id_code ASC +LIMIT 0, 10; + +-- 个人问题库:优化后分页总数 +EXPLAIN +SELECT count(*) FROM ( + SELECT DISTINCT + p.id_code, p.name, p.emp_no, p.position, p.employment_date, p.person_type, + d.short_name depart_name, d.id depart_id, d1.short_name parent_depart_name + + FROM sup_police p + LEFT JOIN sup_depart d ON p.org_id = d.id + LEFT JOIN sup_depart d1 ON d.pid = d1.id AND d1.level >= 2 + WHERE + p.del = 0 + + + + + + AND EXISTS ( + SELECT 1 FROM negative_blame nb + WHERE nb.blameIdCode = p.id_code AND nb.type = 'personal' + AND EXISTS ( + SELECT 1 FROM negative n + WHERE n.id = nb.negativeId + AND + n.checkStatus IN ('1', '2') + AND n.processing_status = 'completed' + AND n.discoveryTime BETWEEN @beginTime AND @endTime + + ) + ) + ) counted; +SHOW WARNINGS; + +SELECT SQL_NO_CACHE count(*) FROM ( + SELECT DISTINCT + p.id_code, p.name, p.emp_no, p.position, p.employment_date, p.person_type, + d.short_name depart_name, d.id depart_id, d1.short_name parent_depart_name + + FROM sup_police p + LEFT JOIN sup_depart d ON p.org_id = d.id + LEFT JOIN sup_depart d1 ON d.pid = d1.id AND d1.level >= 2 + WHERE + p.del = 0 + + + + + + AND EXISTS ( + SELECT 1 FROM negative_blame nb + WHERE nb.blameIdCode = p.id_code AND nb.type = 'personal' + AND EXISTS ( + SELECT 1 FROM negative n + WHERE n.id = nb.negativeId + AND + n.checkStatus IN ('1', '2') + AND n.processing_status = 'completed' + AND n.discoveryTime BETWEEN @beginTime AND @endTime + + ) + ) + ) counted; + +SHOW PROFILES; +SET profiling = 0; diff --git a/src/main/java/com/biutag/supervision/controller/sensitiveperception/ProfileDepartController.java b/src/main/java/com/biutag/supervision/controller/sensitiveperception/ProfileDepartController.java index ca1d0c7..beac13b 100644 --- a/src/main/java/com/biutag/supervision/controller/sensitiveperception/ProfileDepartController.java +++ b/src/main/java/com/biutag/supervision/controller/sensitiveperception/ProfileDepartController.java @@ -87,12 +87,23 @@ public class ProfileDepartController { .setName(depart.getShortName()) .setShortName(depart.getShortName()) .setDepartImg(depart.getImg()); + if (Integer.valueOf(3).equals(depart.getLevel()) && StrUtil.isNotBlank(depart.getPid())) { + SupDepart parent = departService.getById(depart.getPid()); + if (parent != null) { + profileDepart.getDepartInfo().setParentName(StrUtil.blankToDefault(parent.getShortName(), parent.getName())); + } + } } List polices = policeService.listAllByDepartId(departId); profileDepart.getDepartInfo().setMainRole(polices.stream().filter(item -> "正职".equals(item.getPosition())).findFirst().map(SupPolice::getName).orElse(null)); profileDepart.getDepartInfo().setDeputyRole(polices.stream().filter(item -> "副职".equals(item.getPosition())).map(SupPolice::getName).toList()); List negatives = profileDepartMapper.selectDepartProblems(departId, beginTime, endTime); + profileDepart.setComplaintCount(negatives.stream() + .map(Negative::getProblemSourcesCode) + .filter(Objects::nonNull) + .filter(ProblemSourcesEnum.GROUP_21_22_23_24_25::contains) + .count()); List negativeIds = negatives.stream().map(Negative::getId).toList(); SupDepartPoliceSize policeSize = departPoliceSizeService.getById(departId); if(Objects.nonNull(policeSize)){ diff --git a/src/main/java/com/biutag/supervision/pojo/domain/ProfileDepart.java b/src/main/java/com/biutag/supervision/pojo/domain/ProfileDepart.java index 9024284..2839291 100644 --- a/src/main/java/com/biutag/supervision/pojo/domain/ProfileDepart.java +++ b/src/main/java/com/biutag/supervision/pojo/domain/ProfileDepart.java @@ -21,6 +21,8 @@ import java.util.List; public class ProfileDepart { private Long days; + // 信访投诉下级来源的问题数 + private long complaintCount; private BigDecimal score = new BigDecimal(0); private String expression; @@ -60,6 +62,7 @@ public class ProfileDepart { @Accessors(chain = true) public static class DepartInfo { private String name; + private String parentName; private String shortName; private String departImg; // 所长 diff --git a/src/main/java/com/biutag/supervision/pojo/vo/NegativeProfile.java b/src/main/java/com/biutag/supervision/pojo/vo/NegativeProfile.java index a3d42dd..f1bb77f 100644 --- a/src/main/java/com/biutag/supervision/pojo/vo/NegativeProfile.java +++ b/src/main/java/com/biutag/supervision/pojo/vo/NegativeProfile.java @@ -19,6 +19,9 @@ public class NegativeProfile { @JsonFormat(pattern = "yyyy-MM-dd HH:mm") private LocalDateTime discoveryTime; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + private LocalDateTime crtTime; + private String problemSourcesCode; // 问题来源 diff --git a/src/main/resources/mapper/ProfileDepartMapper.xml b/src/main/resources/mapper/ProfileDepartMapper.xml index 06d1e47..778a639 100644 --- a/src/main/resources/mapper/ProfileDepartMapper.xml +++ b/src/main/resources/mapper/ProfileDepartMapper.xml @@ -22,16 +22,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" SELECT count(*) FROM ( SELECT DISTINCT d.id, p.police_size, p.aux_size FROM sup_depart d - LEFT JOIN sup_depart_police_size p ON p.depart_id = d.id + LEFT JOIN sup_depart_police_size p ON p.depart_id = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci WHERE AND EXISTS ( SELECT 1 FROM negative n - WHERE n.involveDepartId = d.id + WHERE n.involveDepartId = CAST(d.id AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci AND n.crtTime BETWEEN #{beginTime} AND #{endTime} ) ) counted + @@ -83,7 +85,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" SELECT nb.blameIdCode, count(DISTINCT n.id) verify_size FROM negative n INNER JOIN negative_blame nb ON nb.negativeId = n.id - WHERE + WHERE nb.type = 'personal' AND GROUP BY nb.blameIdCode ) stats INNER JOIN sup_police p ON p.id_code = stats.blameIdCode diff --git a/src/main/resources/mapper/StatisticsGroupMapper.xml b/src/main/resources/mapper/StatisticsGroupMapper.xml index 7cbf2c9..757706b 100644 --- a/src/main/resources/mapper/StatisticsGroupMapper.xml +++ b/src/main/resources/mapper/StatisticsGroupMapper.xml @@ -76,14 +76,22 @@ `value` DESC + + CASE WHEN m.groupId IN ('20', '21', '22') + AND NULLIF(TRIM(parent_depart.short_name), '') IS NOT NULL + THEN CONCAT(parent_depart.short_name, '/', m.membersName) + ELSE m.membersName END label + + SELECT - membersName label, + , `value`, detail_depart.id detailId FROM negative_group_members m LEFT JOIN sup_depart detail_depart ON detail_depart.id = m.membersCode + LEFT JOIN sup_depart parent_depart ON parent_depart.id = detail_depart.pid LEFT JOIN ( SELECT three_involve_depart_id, @@ -129,13 +138,14 @@