MySQL 统计信息详解:从原理到实践

MySQL 统计信息是数据库优化器生成查询执行计划的关键依据,记录了表和索引的基本特性,辅助优化器估算查询成本、选择最优执行路径。

一、统计信息主要内容

分为表级、索引级和列级三类。

1.1 表级统计信息

描述表基本属性,如行数(TABLE_ROWS)、平均行长度(AVG_ROW_LENGTH)、数据大小(DATA_LENGTH)、索引大小(INDEX_LENGTH)、空闲空间(DATA_FREE)。获取方式:

SELECT TABLE_ROWS, AVG_ROW_LENGTH, DATA_LENGTH, INDEX_LENGTH, DATA_FREE 
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'your_database' AND TABLE_NAME = 'your_table';

1.2 索引级统计信息

描述索引特性,包括基数(CARDINALITY)、索引选择性(CARDINALITY / TOTAL_ROWS)、索引类型(BTREE、FULLTEXT、HASH 等)。可通过 SHOW INDEX FROM your_table; 获取。

1.3 列级统计信息

描述列的数据分布,如最小值和最大值、数据分布、空值计数(NULL_COUNT),通常隐含在优化器行为中。

二、统计信息用途

2.1 查询优化

优化器依据统计信息选择执行计划,如索引扫描、全表扫描、排序方式等。

2.2 估算查询成本

根据行数和索引分布估算读取页面数量,选择最低成本路径。

2.3 JOIN 操作优化

估算表大小,确定 JOIN 顺序和算法,如嵌套循环、哈希连接。

三、统计信息更新

3.1 自动更新

默认自动维护,当表数据变化超 10% 触发,可通过 innodb_stats_auto_recalc 参数(默认 ON)控制。

3.2 手动更新

  • ANALYZE TABLE your_table;:更新表统计信息。
  • OPTIMIZE TABLE your_table;:更新统计信息并整理表和索引。
  • FLUSH TABLES;:刷新表统计信息缓存。

四、统计信息存储与访问

4.1 存储位置

默认存储在内存,重启重新计算。启用 persistent_stats 可持久化到磁盘:

SET PERSIST innodb_stats_persistent = ON;

4.2 查询途径

  • INFORMATION_SCHEMA:TABLES 表查 表级统计信息,STATISTICS 表查索引级统计信息。
  • EXPLAIN SELECT * FROM your_table WHERE column = value;:查询优化器执行计划。

五、统计信息限制

5.1 估算值

统计信息是估算的,表数据频繁变化时不精确。

5.2 锁定统计信息

高并发场景下,更新可能导致性能波动。

5.3 统计信息不足

列数据分布不均时,优化器可能做出次优选择,可通过 ANALYZEUSE INDEX 优化。

六、统计信息优化

6.1 定期维护

ANALYZE TABLEOPTIMIZE TABLE 更新,监控表变化,必要时重新生成。

6.2 持久化统计信息

启用 innodb_stats_persistent 减少重建开销。

6.3 调整采样率

通过 innodb_stats_sample_pages 参数控制采样页面数,默认 8,可提高精度:

SET GLOBAL innodb_stats_sample_pages = 32;

6.4 索引优化

为常用查询添加高选择性索引。

七、全库手动优化统计信息方法

方法 1:INFORMATION_SCHEMA 动态生成命令

SELECT CONCAT('ANALYZE TABLE `', TABLE_SCHEMA, '`.`', TABLE_NAME, '`;')
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE';

方法 2:存储过程自动执行

DELIMITER //
CREATE PROCEDURE UpdateAllStatistics()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE dbName VARCHAR(64);
    DECLARE tblName VARCHAR(64);
    DECLARE cur CURSOR FOR
        SELECT TABLE_SCHEMA, TABLE_NAME 
        FROM INFORMATION_SCHEMA.TABLES
        WHERE TABLE_TYPE = 'BASE TABLE';
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    OPEN cur;
    read_loop: LOOP
        FETCH cur INTO dbName, tblName;
        IF done THEN
            LEAVE read_loop;
        END IF;
        SET @query = CONCAT('ANALYZE TABLE `', dbName, '`.`', tblName, '`');
        PREPARE stmt FROM @query;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END LOOP;
    CLOSE cur;
END;
//
DELIMITER ;

执行:CALL UpdateAllStatistics();

方法 3:Shell 脚本结合 MySQL 客户端

#!/bin/bash
USER="your_user"
PASSWORD="your_password"
HOST="localhost"
mysql -u$USER -p$PASSWORD -h$HOST -N -e "SELECT CONCAT('ANALYZE TABLE \`', TABLE_SCHEMA, '\`.\`', TABLE_NAME, '\`;') FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE';" | mysql -u$USER -p$PASSWORD -h$HOST

八、总结

MySQL 统计信息对优化查询性能至关重要。定期更新和优化可提升查询效率,掌握维护方法是数据库管理员和开发人员必备技能。

欢迎关注公众号《小周的数据库进阶之路》,更多精彩知识和干货尽在其中。

你可能感兴趣的:(mysql,mysql,android,数据库)