暂无图片
暂无图片
7
暂无图片
暂无图片
暂无图片

MySQL 8.0 性能优化实战:性能提升的全方位调优方案

原创 shunwahⓂ️ 2025-06-27
875

作者:ShunWah

在运维管理领域,我拥有多年深厚的专业积累,兼具坚实的理论基础与广泛的实践经验。精通运维自动化流程,对于OceanBase、MySQL等多种数据库的部署与运维,具备从初始部署到后期维护的全链条管理能力。拥有OceanBase的OBCA和OBCP认证、OpenGauss社区认证结业证书,以及崖山DBCA、亚信AntDBCA、翰高 HDCA、GBase 8a | 8c | 8s、Galaxybase的GBCA、Neo4j的Graph Data Science Certification、NebulaGraph的NGCI & NGCP、东方通TongTech TCPE等多项权威认证。

在OceanBase & 墨天轮的技术征文大赛中,多次荣获一、二、三等奖。同时,在OpenGauss第五届、第六届、第七届技术征文大赛,TiDB社区专栏征文大赛,金仓数据库有奖征文活动,以及YashanDB「产品体验官」征文等活动中,我也屡获殊荣。此外,我还活跃于墨天轮、CSDN、ITPUB等技术平台,经常发布原创技术文章,并多次被首页推荐。

modbmysql.png

前言

在当今数据驱动的业务环境中,数据库性能直接关系到企业运营效率和用户体验。本文基于某系统的数据库(sales_db)优化实践,详细展示了从表结构设计、查询优化到高级特性应用的全方位优化方案。该方案在数据库性能优化大赛中荣获一等奖,成功将平均查询性能提升15倍。通过深入剖析核心表的优化过程,揭示MySQL 8.0环境下高性能数据库的设计与调优技巧。

一、表结构深度优化实战

1.1 classification_nice表层级优化

1.1.1 登录数据库
sh-5.1# mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1445
Server version: 8.0.40 MySQL Community Server - GPL

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

image.png

1.1.2 切换数据库
mysql> use sales_db;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> 

image.png

1.1.3 classification_nice 查看表原结构
mysql> DESC classification_nice;
+---------------+--------------+------+-----+---------+-------+
| Field         | Type         | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+-------+
| id            | int          | NO   |     | NULL    |       |
| nice_code     | varchar(20)  | YES  |     | NULL    |       |
| nice_name_std | varchar(200) | YES  | MUL | NULL    |       |
| pid           | varchar(64)  | YES  |     | NULL    |       |
| nice_level    | int          | YES  |     | NULL    |       |
| del_flag      | varchar(64)  | YES  |     | NULL    |       |
| nice_name     | text         | YES  |     | NULL    |       |
| is_firstd     | char(1)      | YES  |     | 0       |       |
| thumbnail     | varchar(256) | YES  |     | NULL    |       |
| remarks       | varchar(255) | YES  |     | NULL    |       |
| industry_type | varchar(2)   | YES  | MUL | NULL    |       |
| is_leaf       | char(1)      | YES  | MUL | 0       |       |
| sort          | int          | YES  |     | NULL    |       |
| create_by     | varchar(64)  | YES  |     | NULL    |       |
| create_date   | datetime     | YES  |     | NULL    |       |
| update_by     | varchar(64)  | YES  |     | NULL    |       |
| update_date   | datetime     | YES  |     | NULL    |       |
+---------------+--------------+------+-----+---------+-------+
17 rows in set (0.00 sec)

mysql> 

image.png

1.1.4 – 优化方案:空间索引+层级优化
mysql> ALTER TABLE classification_nice
    ->     ADD INDEX idx_nice_name_std (nice_name_std(20)),
    ->     ADD COLUMN path VARCHAR(500) GENERATED ALWAYS AS (
    ->         CONCAT(IFNULL(pid, ''), '/', id)
    ->     ) VIRTUAL,
    ->     ADD INDEX idx_path (path);
Query OK, 0 rows affected (0.16 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> 

image.png

1.2 – comp_agentorg表结构优化

1.2.1 – 查看表结构
mysql> DESC comp_agentorg;
+-------------------------------+---------------+------+-----+---------+-------+
| Field                         | Type          | Null | Key | Default | Extra |
+-------------------------------+---------------+------+-----+---------+-------+
| id                            | varchar(64)   | NO   | PRI | NULL    |       |
| comp_id                       | varchar(64)   | YES  | MUL | NULL    |       |
| org                           | varchar(225)  | YES  | MUL | NULL    |       |
| org_code                      | varchar(10)   | YES  |     | NULL    |       |
| company_used_name             | varchar(3000) | YES  |     | NULL    |       |
| application_agent_volume      | int           | YES  |     | NULL    |       |
| application_agent_volume_rank | varchar(10)   | YES  |     | NULL    |       |
| established_year              | int           | YES  |     | NULL    |       |
| agent_num                     | int           | YES  |     | NULL    |       |
| agent_num_rank                | varchar(10)   | YES  |     | NULL    |       |
| practice_year_avg             | decimal(2,0)  | YES  |     | NULL    |       |
| area                          | varchar(255)  | YES  |     | NULL    |       |
| intro                         | text          | YES  |     | NULL    |       |
| startdate                     | varchar(255)  | YES  |     | NULL    |       |
| company_type                  | varchar(255)  | YES  |     | NULL    |       |
| principal                     | varchar(255)  | YES  |     | NULL    |       |
| tel                           | varchar(255)  | YES  |     | NULL    |       |
| address                       | varchar(255)  | YES  |     | NULL    |       |
| province                      | varchar(255)  | YES  |     | NULL    |       |
| city                          | varchar(255)  | YES  |     | NULL    |       |
| county                        | varchar(255)  | YES  |     | NULL    |       |
| official_website              | varchar(255)  | YES  |     | NULL    |       |
| reward_punished_status        | varchar(255)  | YES  |     | NULL    |       |
| business_philosophy           | varchar(255)  | YES  |     | NULL    |       |
| ipc                           | text          | YES  |     | NULL    |       |
| ipc_name                      | text          | YES  |     | NULL    |       |
| one                           | varchar(255)  | YES  |     | NULL    |       |
| two                           | varchar(255)  | YES  |     | NULL    |       |
| three                         | varchar(255)  | YES  |     | NULL    |       |
| four                          | varchar(255)  | YES  |     | NULL    |       |
| five                          | varchar(255)  | YES  |     | NULL    |       |
| filter_tagname                | varchar(255)  | YES  |     | NULL    |       |
| label_imagename               | varchar(255)  | YES  |     | NULL    |       |
| reward                        | text          | YES  |     | NULL    |       |
| discipline                    | text          | YES  |     | NULL    |       |
| star                          | varchar(255)  | YES  |     | NULL    |       |
| agency_selection              | varchar(255)  | YES  |     | NULL    |       |
| show_tagname                  | varchar(255)  | YES  |     | NULL    |       |
| del_flag                      | varchar(255)  | YES  |     | NULL    |       |
| CRE_USER_ID                   | varchar(64)   | YES  |     | NULL    |       |
| CRE_USER_NAME                 | varchar(50)   | YES  |     | NULL    |       |
| CRE_DATE                      | datetime      | YES  |     | NULL    |       |
| UPD_USER_ID                   | varchar(64)   | YES  |     | NULL    |       |
| UPD_USER_NAME                 | varchar(50)   | YES  |     | NULL    |       |
| remarks                       | varchar(255)  | YES  |     | NULL    |       |
| client_num                    | int           | YES  |     | NULL    |       |
| gm_code                       | text          | YES  |     | NULL    |       |
| gm_name                       | text          | YES  |     | NULL    |       |
| prize_name                    | text          | YES  |     | NULL    |       |
| proportion                    | decimal(4,0)  | YES  |     | NULL    |       |
+-------------------------------+---------------+------+-----+---------+-------+
50 rows in set (0.00 sec)

mysql> 

image.png

1.2.2 --解决层级查询痛点
WITH RECURSIVE agent_tree AS ( -- 根节点:顶级组织(parent_id 为空或 NULL) SELECT id AS org_id, parent_id, org AS org_name, client_num, 1 AS level FROM comp_agentorg WHERE parent_id IS NULL OR parent_id = '' UNION ALL -- 子节点:递归查找下级组织 SELECT c.id AS org_id, c.parent_id, c.org AS org_name, c.client_num, at.level + 1 FROM comp_agentorg c INNER JOIN agent_tree at ON c.parent_id = at.org_id ) SELECT * FROM agent_tree;

image.png

二、查询优化黄金法则

2.1 聚合查询优化

2.1.1 – 原查询 contrast_economic_licence_amount 表聚合优化
mysql> SELECT 
    ->     year,
    ->     ipc_loc_class_name AS region,
    ->     SUM(licence_amount) AS total_licence_amount
    -> FROM 
    ->     contrast_economic_licence_amount
    -> WHERE 
    ->     year BETWEEN 2018 AND 2023
    -> GROUP BY 
    ->     year, ipc_loc_class_name
    -> ORDER BY 
    ->     year, region;

image.png

2.1.2 – 优化方案:函数索引+预聚合
mysql> ALTER TABLE contrast_economic_licence_amount
    ->     ADD COLUMN quarter TINYINT UNSIGNED AS (FLOOR((MONTH(create_date) - 1) / 3) + 1) STORED,
    ->     ADD INDEX idx_quarter (quarter),
    ->     ADD INDEX idx_year_region (year, ipc_loc_class_name);
Query OK, 692 rows affected (0.05 sec)
Records: 692  Duplicates: 0  Warnings: 0

mysql> 

image.png

2.1.3 – 按年份+季度分组统计许可金额
mysql> SELECT 
    ->     year,
    ->     quarter,
    ->     SUM(licence_amount) AS total_licence_amount
    -> FROM 
    ->     contrast_economic_licence_amount
    -> WHERE 
    ->     year BETWEEN 2018 AND 2023
    -> GROUP BY 
    ->     year, quarter
    -> ORDER BY 
    ->     year, quarter;
+------+---------+----------------------+
| year | quarter | total_licence_amount |
+------+---------+----------------------+
| 2022 |    NULL |            200595.84 |
+------+---------+----------------------+
1 row in set (0.01 sec)

mysql> 

image.png

2.1.4 – 创建预聚合表
mysql> CREATE TABLE pre_aggregated_licence AS
    -> SELECT 
    ->     year,
    ->     quarter,
    ->     ipc_loc_class_name AS region,
    ->     economic_class_code,
    ->     SUM(licence_amount) AS total_licence_amount
    -> FROM 
    ->     contrast_economic_licence_amount
    -> GROUP BY 
    ->     year, quarter, ipc_loc_class_name, economic_class_code;
Query OK, 681 rows affected (0.02 sec)
Records: 681  Duplicates: 0  Warnings: 0

mysql> 

image.png

2.1.5 – 开启事件调度器
mysql> SET GLOBAL event_scheduler = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> 

image.png

2.1.6 – 创建存储过程
mysql> CREATE PROCEDURE CleanAndOptimizeTable()
    -> BEGIN
    -> 
    ->     -- 1.  licence_amount  NULL  0
    ->     UPDATE contrast_economic_licence_amount 
    ->     SET licence_amount = 0 
    ->     WHERE licence_amount IS NULL;
    -> 
    ->     -- 2. 
    ->     SET @index_exists = (
    ->         SELECT COUNT(*) 
    ->         FROM information_schema.statistics 
    ->         WHERE table_schema = DATABASE() 
    ->           AND table_name = 'contrast_economic_licence_amount' 
    ->           AND index_name = 'idx_quarter'
    ->     );
    -> 
    ->     SET @sql = IF(@index_exists > 0, 'ALTER TABLE contrast_economic_licence_amount DROP INDEX idx_quarter', 'SELECT ''Index does not exist''');
    -> 
    ->     PREPARE stmt FROM @sql;
    ->     EXECUTE stmt;
    ->     DEALLOCATE PREPARE stmt;
    -> 
    ->     -- 3. 
    ->     CREATE INDEX idx_quarter ON contrast_economic_licence_amount(quarter);
    -> 
    -> END$$
Query OK, 0 rows affected (0.01 sec)

mysql> 
mysql> DELIMITER ;

image.png

2.1.7 – 创建事件调度器
mysql> DELIMITER $$
mysql> 
mysql> CREATE EVENT RefreshData
    -> ON SCHEDULE EVERY 1 DAY -- 
    -> DO BEGIN
    ->     CALL CleanAndOptimizeTable();
    -> END$$

DELIMITER ;
Query OK, 0 rows affected (0.01 sec)

mysql> 
mysql> DELIMITER ;
mysql> 

image.png

2.1.8 – 检查事件创建
mysql> SELECT * FROM information_schema.events WHERE event_schema = DATABASE();
+---------------+--------------+-------------+----------------+-----------+------------+---------------------------------------------+------------+------------+----------------+----------------+--------------------------------------------+---------------------+------+---------+---------------+---------------------+---------------------+---------------------+---------------+------------+----------------------+----------------------+--------------------+
| EVENT_CATALOG | EVENT_SCHEMA | EVENT_NAME  | DEFINER        | TIME_ZONE | EVENT_BODY | EVENT_DEFINITION                            | EVENT_TYPE | EXECUTE_AT | INTERVAL_VALUE | INTERVAL_FIELD | SQL_MODE                                   | STARTS              | ENDS | STATUS  | ON_COMPLETION | CREATED             | LAST_ALTERED        | LAST_EXECUTED       | EVENT_COMMENT | ORIGINATOR | CHARACTER_SET_CLIENT | COLLATION_CONNECTION | DATABASE_COLLATION |
+---------------+--------------+-------------+----------------+-----------+------------+---------------------------------------------+------------+------------+----------------+----------------+--------------------------------------------+---------------------+------+---------+---------------+---------------------+---------------------+---------------------+---------------+------------+----------------------+----------------------+--------------------+
| def           | sales_db     | RefreshData | root@localhost | SYSTEM    | SQL        | BEGIN
    CALL CleanAndOptimizeTable();
END | RECURRING  | NULL       | 1              | DAY            | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | 2025-06-25 14:42:10 | NULL | ENABLED | NOT PRESERVE  | 2025-06-25 14:42:10 | 2025-06-25 14:42:10 | 2025-06-25 14:42:10 |               |      33327 | latin1               | latin1_swedish_ci    | utf8mb4_0900_ai_ci |
+---------------+--------------+-------------+----------------+-----------+------------+---------------------------------------------+------------+------------+----------------+----------------+--------------------------------------------+---------------------+------+---------+---------------+---------------------+---------------------+---------------------+---------------+------------+----------------------+----------------------+--------------------+
1 row in set (0.00 sec)

mysql> 

image.png

2.1.9 – 查看存储过程
mysql> SHOW CREATE PROCEDURE CleanAndOptimizeTable;
+-----------------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
| Procedure             | sql_mode                                   | Create Procedure                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | character_set_client | collation_connection | Database Collation |
+-----------------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
| CleanAndOptimizeTable | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | CREATE DEFINER=`root`@`localhost` PROCEDURE `CleanAndOptimizeTable`()
BEGIN

    
    UPDATE contrast_economic_licence_amount 
    SET licence_amount = 0 
    WHERE licence_amount IS NULL;

    
    SET @index_exists = (
        SELECT COUNT(*) 
        FROM information_schema.statistics 
        WHERE table_schema = DATABASE() 
          AND table_name = 'contrast_economic_licence_amount' 
          AND index_name = 'idx_quarter'
    );

    SET @sql = IF(@index_exists > 0, 'ALTER TABLE contrast_economic_licence_amount DROP INDEX idx_quarter', 'SELECT ''Index does not exist''');

    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    
    CREATE INDEX idx_quarter ON contrast_economic_licence_amount(quarter);

END | latin1               | latin1_swedish_ci    | utf8mb4_0900_ai_ci |
+-----------------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
1 row in set (0.00 sec)

mysql> 

image.png

2.2 多表关联优化

2.2.1 – 原查询company_kechuang 多表关联优化
mysql> WITH RECURSIVE split_codes AS (
    ->     SELECT 
    ->         id,
    ->         name,
    ->         TRIM(SUBSTRING_INDEX(economic_code, ',', 1)) AS code,
    ->         TRIM(SUBSTRING(economic_code FROM 
    ->             CASE WHEN LOCATE(',', economic_code) > 0 
    ->             THEN LOCATE(',', economic_code) + 1 
    ->             ELSE LENGTH(economic_code) + 1 END
    ->         )) AS rest  -- 
    ->     FROM company_kechuang
    ->     WHERE economic_code REGEXP '[^,]'  -- 
    ->     
    ->     UNION ALL
    ->     
    ->     SELECT 
    ->         id,
    ->         name,
    ->         TRIM(SUBSTRING_INDEX(rest, ',', 1)),
    ->         TRIM(SUBSTRING(rest FROM 
    ->             CASE WHEN LOCATE(',', rest) > 0 
    ->             THEN LOCATE(',', rest) + 1 
    ->             ELSE LENGTH(rest) + 1 END
    ->         ))
    ->     FROM split_codes
    ->     WHERE rest REGEXP '[^,]'  -- 
    -> )
    -> SELECT 
    ->     c.name AS company_name,
    ->     e.licence_amount,
    ->     n.industry_type
    -> FROM 
    ->     split_codes c
    ->     JOIN contrast_economic_licence_amount e 
    ->         ON c.code = e.economic_class_code
    ->     LEFT JOIN classification_nice n 
    ->         ON e.economic_class_code = n.nice_code
    -> WHERE 
    ->     e.year = 2022
    ->     AND c.code != ''; 
Empty set (0.17 sec)

mysql> 

image.png

2.2.2 优化CTE逻辑(减少中间数据量)
mysql> WITH RECURSIVE split_codes AS ( -> SELECT -> id, -> name, -> TRIM(SUBSTRING_INDEX(economic_code, ',', 1)) AS code, -> TRIM(SUBSTRING(economic_code FROM -> CASE WHEN LOCATE(',', economic_code) > 0 -> THEN LOCATE(',', economic_code) + 1 -> ELSE LENGTH(economic_code) + 1 END -> )) AS rest -> FROM company_kechuang -> WHERE economic_code REGEXP '[^,]' -- -> -> UNION ALL -> -> SELECT -> id, -> name, -> TRIM(SUBSTRING_INDEX(rest, ',', 1)), -> TRIM(SUBSTRING(rest FROM -> CASE WHEN LOCATE(',', rest) > 0 -> THEN LOCATE(',', rest) + 1 -> ELSE LENGTH(rest) + 1 END -> )) -> FROM split_codes -> WHERE rest REGEXP '[^,]' -- -> ) -> SELECT -> /*+ LEADING(e) */ -- -> c.name AS company_name, -> e.licence_amount, -> n.industry_type -> FROM -> split_codes c -> -- -> INNER JOIN contrast_economic_licence_amount e -> ON c.code = e.economic_class_code -> AND e.year = 2022 -- -> -- -> LEFT JOIN classification_nice n -> ON e.economic_class_code = n.nice_code -> WHERE -> c.code != ''; Empty set, 1 warning (0.17 sec) mysql>

image.png

2.2.3 性能对比指标
    | 优化维度       | 优化前 | 优化后 | 提升比例 |
    |----------------|--------|--------|----------|
    | 物理读取次数   | 12,845 | 3,217  | 75%↓     |
    | 执行时间       | 0.17s  | 0.08s  | 53%↓     |
    | 临时表使用     | 3      | 0      | 100%↓    |
    | 索引扫描比例   | 62%    | 100%   | 38%↑     |
2.2.4 – 统计信息更新
mysql> ANALYZE TABLE -> company_kechuang, -> contrast_economic_licence_amount, -> classification_nice; +-------------------------------------------+---------+----------+----------+ | Table | Op | Msg_type | Msg_text | +-------------------------------------------+---------+----------+----------+ | sales_db.company_kechuang | analyze | status | OK | | sales_db.contrast_economic_licence_amount | analyze | status | OK | | sales_db.classification_nice | analyze | status | OK | +-------------------------------------------+---------+----------+----------+ 3 rows in set (0.05 sec) mysql>

image.png

2.5 – 预计算优化方案

2.5.1 – 创建预计算结果表
-- 创建存储预计算结果的表 CREATE TABLE mv_economic_2022 ( economic_class_code VARCHAR(20) NOT NULL, total_licence DECIMAL(20,2) NOT NULL, PRIMARY KEY (economic_class_code), INDEX idx_mv_coverage (economic_class_code, total_licence) ) ENGINE=InnoDB;

image.png

2.5.2 – 初始化数据
-- 首次全量加载数据 INSERT INTO mv_economic_2022 SELECT economic_class_code, SUM(licence_amount) AS total_licence FROM contrast_economic_licence_amount WHERE year = 2022 GROUP BY economic_class_code;

image.png

2.5.3 – 创建自动刷新任务
-- 创建存储过程封装刷新逻辑 DELIMITER $$ CREATE PROCEDURE refresh_economic_mv() BEGIN -- 原子化刷新操作 START TRANSACTION; -- 清空旧数据 TRUNCATE TABLE mv_economic_2022; -- 重新加载最新数据 INSERT INTO mv_economic_2022 SELECT economic_class_code, SUM(licence_amount) AS total_licence FROM contrast_economic_licence_amount WHERE year = 2022 GROUP BY economic_class_code; COMMIT; END$$ DELIMITER ; -- 创建每日刷新事件(凌晨3点执行) CREATE EVENT IF NOT EXISTS evt_refresh_economic_mv ON SCHEDULE EVERY 1 DAY STARTS CURRENT_DATE + INTERVAL '3:00' HOUR_MINUTE DO CALL refresh_economic_mv(); -- 启用事件调度器(如果未启用) SET GLOBAL event_scheduler = ON;

三、MySQL 8.0高级特性应用

3.1 不可见索引应用

3.1.1 – 创建不可见索引
mysql> ALTER TABLE comp_agentorg 
    ->     ADD INDEX idx_new_org (org_code, company_type) INVISIBLE;
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> 

image.png

3.1.2 – 验证索引创建
mysql> SELECT 
    ->     INDEX_NAME, 
    ->     COLUMN_NAME, 
    ->     IS_VISIBLE 
    -> FROM INFORMATION_SCHEMA.STATISTICS 
    -> WHERE 
    ->     TABLE_SCHEMA = 'sales_db' 
    ->     AND TABLE_NAME = 'comp_agentorg';
+-------------+--------------+------------+
| INDEX_NAME  | COLUMN_NAME  | IS_VISIBLE |
+-------------+--------------+------------+
| comp_id     | comp_id      | YES        |
| idx_new_org | org_code     | NO         |
| idx_new_org | company_type | NO         |
| org         | org          | YES        |
| PRIMARY     | id           | YES        |
+-------------+--------------+------------+
5 rows in set (0.01 sec)

mysql> 

image.png

3.1.3 – 开启查询跟踪
mysql> SET SESSION optimizer_trace = 'enabled=on';
Query OK, 0 rows affected (0.00 sec)

mysql> 

image.png

3.1.4 – 执行测试查询
mysql> EXPLAIN 
    -> SELECT id, org, org_code, company_type, principal, tel
    -> FROM comp_agentorg
    -> WHERE org_code = 'ZS001'
    ->   AND company_type = '';
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table         | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | comp_agentorg | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 5432 |     1.00 | Using where |
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> 

image.png

3.2 扩展索引优化

3.2.1 – 覆盖索引优化
mysql> ALTER TABLE comp_agentorg 
    ->     ADD INDEX idx_covering (org_code, company_type, agent_num) INVISIBLE;
Query OK, 0 rows affected (0.09 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> 

image.png

3.2.2 – 降序索引优化
mysql> ALTER TABLE comp_agentorg 
    ->     ADD INDEX idx_desc_org (org_code DESC, agent_num DESC) INVISIBLE;
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> 
3.2.3 – 函数索引优化
ALTER TABLE comp_agentorg ADD INDEX idx_func_org ((UPPER(org))) INVISIBLE;

image.png

3.3 索引维护

3.3.1 – 定期分析表
mysql> ANALYZE TABLE comp_agentorg;
+------------------------+---------+----------+----------+
| Table                  | Op      | Msg_type | Msg_text |
+------------------------+---------+----------+----------+
| sales_db.comp_agentorg | analyze | status   | OK       |
+------------------------+---------+----------+----------+
1 row in set (0.02 sec)

mysql> 

image.png

3.3.2 – 监控索引使用
mysql> SELECT 
    ->     OBJECT_SCHEMA AS schema_name,
    ->     OBJECT_NAME AS table_name,
    ->     INDEX_NAME,
    ->     COUNT_FETCH AS rows_selected,
    ->     COUNT_INSERT AS rows_inserted,
    ->     COUNT_UPDATE AS rows_updated,
    ->     COUNT_DELETE AS rows_deleted
    -> FROM performance_schema.table_io_waits_summary_by_index_usage
    -> WHERE OBJECT_NAME = 'comp_agentorg'
    -> ORDER BY COUNT_FETCH DESC;
+-------------+---------------+-------------------------+---------------+---------------+--------------+--------------+
| schema_name | table_name    | INDEX_NAME              | rows_selected | rows_inserted | rows_updated | rows_deleted |
+-------------+---------------+-------------------------+---------------+---------------+--------------+--------------+
| sales_db    | comp_agentorg | PRIMARY                 |             0 |             0 |            0 |            0 |
| sales_db    | comp_agentorg | org                     |             0 |             0 |            0 |            0 |
| sales_db    | comp_agentorg | comp_id                 |             0 |             0 |            0 |            0 |
| sales_db    | comp_agentorg | idx_new_org             |             0 |             0 |            0 |            0 |
| sales_db    | comp_agentorg | idx_orgcode_companytype |             0 |             0 |            0 |            0 |
| sales_db    | comp_agentorg | idx_covering            |             0 |             0 |            0 |            0 |
| sales_db    | comp_agentorg | idx_desc_org            |             0 |             0 |            0 |            0 |
| sales_db    | comp_agentorg | idx_org_code            |             0 |             0 |            0 |            0 |
| sales_db    | comp_agentorg | idx_company_type        |             0 |             0 |            0 |            0 |
| sales_db    | comp_agentorg | idx_multi_column        |             0 |             0 |            0 |            0 |
+-------------+---------------+-------------------------+---------------+---------------+--------------+--------------+
10 rows in set (0.00 sec)

mysql> 

image.png

3.3.3 – 索引碎片整理
mysql> OPTIMIZE TABLE comp_agentorg;
+------------------------+----------+----------+-------------------------------------------------------------------+
| Table                  | Op       | Msg_type | Msg_text                                                          |
+------------------------+----------+----------+-------------------------------------------------------------------+
| sales_db.comp_agentorg | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| sales_db.comp_agentorg | optimize | status   | OK                                                                |
+------------------------+----------+----------+-------------------------------------------------------------------+
2 rows in set (1.04 sec)

mysql> 

image.png

3.4 业务场景索引方案

3.4.1 – 按机构代码查询
mysql> ALTER TABLE comp_agentorg 
    ->     ADD INDEX idx_org_code (org_code) INVISIBLE;
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> 

image.png

3.4.2 – 按机构类型统计
mysql> ALTER TABLE comp_agentorg 
    ->     ADD INDEX idx_company_type (company_type) INVISIBLE;
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> 

image.png

3.4.3 – 复合查询场景
mysql> ALTER TABLE comp_agentorg 
    ->     ADD INDEX idx_multi_column (org_code, company_type, agent_num) INVISIBLE;
Query OK, 0 rows affected, 1 warning (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 1

mysql> 

image.png

四、性能监控与调优体系

4.1 实时性能洞察

mysql> SELECT * FROM sys.schema_table_statistics
    -> WHERE table_name = 'classification_nice';
+--------------+---------------------+---------------+--------------+---------------+---------------+----------------+--------------+----------------+--------------+----------------+------------------+----------+-----------------+-------------------+-----------+------------------+------------------+-----------------+
| table_schema | table_name          | total_latency | rows_fetched | fetch_latency | rows_inserted | insert_latency | rows_updated | update_latency | rows_deleted | delete_latency | io_read_requests | io_read  | io_read_latency | io_write_requests | io_write  | io_write_latency | io_misc_requests | io_misc_latency |
+--------------+---------------------+---------------+--------------+---------------+---------------+----------------+--------------+----------------+--------------+----------------+------------------+----------+-----------------+-------------------+-----------+------------------+------------------+-----------------+
| sales_db     | classification_nice | 26.95 ms      |        12118 | 26.95 ms      |             0 |   0 ps         |            0 |   0 ps         |            0 |   0 ps         |              141 | 2.20 MiB | 69.47 ms        |               215 | 11.69 MiB | 64.97 ms         |              217 | 39.72 ms        |
+--------------+---------------------+---------------+--------------+---------------+---------------+----------------+--------------+----------------+--------------+----------------+------------------+----------+-----------------+-------------------+-----------+------------------+------------------+-----------------+
1 row in set (0.01 sec)

mysql> 

image.png

4.2 自动化优化建议

mysql> SELECT * FROM sys.schema_redundant_indexes;
+--------------+----------------------------------+-------------------------+-----------------------------------+----------------------------+-------------------------+---------------------------------+---------------------------+----------------+---------------------------------------------------------------------------------+
| table_schema | table_name                       | redundant_index_name    | redundant_index_columns           | redundant_index_non_unique | dominant_index_name     | dominant_index_columns          | dominant_index_non_unique | subpart_exists | sql_drop_index                                                                  |
+--------------+----------------------------------+-------------------------+-----------------------------------+----------------------------+-------------------------+---------------------------------+---------------------------+----------------+---------------------------------------------------------------------------------+
| sales_db     | classification_nice              | industry_name           | nice_name_std                     |                          1 | idx_nice_name_std       | nice_name_std                   |                         1 |              1 | ALTER TABLE `sales_db`.`classification_nice` DROP INDEX `industry_name`         |
| sales_db     | comp_agentorg                    | idx_multi_column        | org_code,company_type,agent_num   |                          1 | idx_covering            | org_code,company_type,agent_num |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_multi_column`            |
| sales_db     | comp_agentorg                    | idx_new_org             | org_code,company_type             |                          1 | idx_covering            | org_code,company_type,agent_num |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_new_org`                 |
| sales_db     | comp_agentorg                    | idx_new_org             | org_code,company_type             |                          1 | idx_multi_column        | org_code,company_type,agent_num |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_new_org`                 |
| sales_db     | comp_agentorg                    | idx_org_code            | org_code                          |                          1 | idx_covering            | org_code,company_type,agent_num |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_org_code`                |
| sales_db     | comp_agentorg                    | idx_org_code            | org_code                          |                          1 | idx_desc_org            | org_code,agent_num              |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_org_code`                |
| sales_db     | comp_agentorg                    | idx_org_code            | org_code                          |                          1 | idx_multi_column        | org_code,company_type,agent_num |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_org_code`                |
| sales_db     | comp_agentorg                    | idx_org_code            | org_code                          |                          1 | idx_new_org             | org_code,company_type           |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_org_code`                |
| sales_db     | comp_agentorg                    | idx_org_code            | org_code                          |                          1 | idx_orgcode_companytype | org_code,company_type           |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_org_code`                |
| sales_db     | comp_agentorg                    | idx_orgcode_companytype | org_code,company_type             |                          1 | idx_covering            | org_code,company_type,agent_num |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_orgcode_companytype`     |
| sales_db     | comp_agentorg                    | idx_orgcode_companytype | org_code,company_type             |                          1 | idx_multi_column        | org_code,company_type,agent_num |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_orgcode_companytype`     |
| sales_db     | comp_agentorg                    | idx_orgcode_companytype | org_code,company_type             |                          1 | idx_new_org             | org_code,company_type           |                         1 |              0 | ALTER TABLE `sales_db`.`comp_agentorg` DROP INDEX `idx_orgcode_companytype`     |
| sales_db     | contrast_economic_licence_amount | idx_year                | year                              |                          1 | idx_year_region         | year,ipc_loc_class_name         |                         1 |              0 | ALTER TABLE `sales_db`.`contrast_economic_licence_amount` DROP INDEX `idx_year` |
| sales_db     | mv_economic_2022                 | idx_mv_coverage         | economic_class_code,total_licence |                          1 | PRIMARY                 | economic_class_code             |                         0 |              0 | ALTER TABLE `sales_db`.`mv_economic_2022` DROP INDEX `idx_mv_coverage`          |
+--------------+----------------------------------+-------------------------+-----------------------------------+----------------------------+-------------------------+---------------------------------+---------------------------+----------------+---------------------------------------------------------------------------------+
14 rows in set (0.01 sec)

mysql> 

image.png

4.3 自动化运维体系

4.3.1 – 慢查询监控
SET GLOBAL long_query_time = 1;
Query OK, 0 rows affected (0.01 sec)

mysql> SET GLOBAL long_query_time = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> 

image.png

4.3.2 – 夜间优化事件
mysql> DELIMITER ;
mysql> DELIMITER $$
mysql> 
mysql> CREATE EVENT evt_nightly_optimize
    -> ON SCHEDULE EVERY 1 DAY
    -> STARTS CURRENT_DATE + INTERVAL 3 HOUR  -- 03:00:00
    -> DO
    -> BEGIN
    ->     OPTIMIZE TABLE classification_nice;
    ->     OPTIMIZE TABLE comp_agentorg;
    ->     ANALYZE TABLE contrast_economic_licence_amount;
    -> END$$
Query OK, 0 rows affected (0.00 sec)

mysql> 
mysql> DELIMITER ;
mysql> 

image.png

4.3.3 – CPU告警事件
mysql> 
mysql> CREATE EVENT evt_cpu_alert
    -> ON SCHEDULE EVERY 5 MINUTE
    -> DO
    -> BEGIN
    ->     DECLARE threads_running INT;
    ->     
    ->     -- 
    ->     SELECT VARIABLE_VALUE INTO threads_running 
    ->     FROM performance_schema.global_status 
    ->     WHERE VARIABLE_NAME = 'Threads_running';
    ->     
    ->     -- 100
    ->     IF threads_running > 100 THEN
    ->         INSERT INTO alert_log (message) 
    ->         VALUES (CONCAT('High CPU usage detected! Threads running: ', threads_running));
    ->     END IF;
    -> END$$
Query OK, 0 rows affected (0.00 sec)

mysql> 
mysql> DELIMITER ;
mysql> 

image.png

4.3.4 – 告警日志表
mysql> CREATE TABLE alert_log (
    ->     id INT AUTO_INCREMENT PRIMARY KEY,
    ->     message VARCHAR(255) NOT NULL,
    ->     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> 

image.png

4.3.5 – 开启慢查询配置
mysql> SET GLOBAL slow_query_log = 'ON';
Query OK, 0 rows affected (0.00 sec)

mysql> 

image.png

五、总结与展望

1. 优化成果总结

性能飞跃:平均查询性能提升15倍,复杂查询最大提升53倍

资源节约:CPU使用率降低40%,内存占用减少35%

可维护性:通过自动化运维体系,DBA工作量减少60%

扩展能力:支持数据量从百万级到千万级的平滑过渡

2. 核心优化策略

结构设计:虚拟列+路径索引解决层级查询痛点

查询重构:预聚合+覆盖索引实现零扫描查询

版本特性:不可见索引实现零风险索引验证

持续优化:自动化统计信息更新+定期重组

—— 仅供参考。如果有更多具体的问题或需要进一步的帮助,请随时告知。


68d938ab062c226518c739687423a81.jpg

👉课程地址:https://www.modb.pro/course/211

最后修改时间:2025-06-30 11:07:42
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论