MYSQL 如果索引优化仅仅是添加索引,too young to simple
MYSQL 的索引优化,如果此时此刻看到索引的优化,仅仅想到添加适合的索引,是不完全的,索引的优化本身就具有很多的不确定性。
1 索引会随着时间的推移,有性能的衰减
2 索引会随着数据量的增加,有性能的衰减
3 数据表随着业务的扩展,增加字段,条件的变化,索引变得不在有效或成为性能的阻碍
4 索引在一个表中本身的数量增加,对数据的插入和DML操作产生性能问题
所以索引 ≠ 性能优化,无序的操作可能造成 索引 = 性能需要优化。
那我们看看以上的问题是怎么产生的
1 每个表都会进行DML 操作,其中基于BTREE + 的原理,索引本身是有序的,而随机的数据的插入,在索引中的体现就是索引页的物理顺序不接近逻辑顺序,大白话就是索引本身占有的空间,对比实际占有的空间要小。
select ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free,table_schema from information_schema.tables where DATA_FREE > 0;
上面的语句就可以让你清晰的看出一个表中的数据和索引的大小以及其中碎片的大小,通过上面的语句还可以演化出,计算表的碎片率的语句。
通过分析可以知道这些表的碎片水平,一个碎片率很高的表,本身就是对索引的一种消耗。(如果碎片率高,就需要通过整理碎片来提高性能)
以上就是随着时间的推移,索引的衰减
2 数据量的加大,索引的衰减,这点与MYSQL的表的BTREE+的数据存储雷同,基于索引本身随着数据流的加大,根+叶子节点可能会发展到超过3层的可能,那么查询数据必然会到更深层次的叶子节点去搜寻,那么这也数据索引的衰减的因素之一。
3 一个数据表是随着业务的变化而变化的,相关的查询的条件也是变化的,之前的查询条件,随着新的字段的加入,条件的变化导致索引可能不在和以前最初设计他的时候一样有效,所以时刻获取索引在数据库的状态也是重要的。
下面就通过各种语句,来获取索引的状态,动态调整索引,及时添加或清理失效的索引。
1 查看全表扫描的信息
select db,query,total_latency/exec_count as avg_latency_us,no_index_used_count from sys.statements_with_full_table_scans;
通过这个信息查看通过全表扫描的语句以及这些语句消耗的时间,通过执行的次数以及执行时间的信息,来判断这个语句是否需要进行优化,或是因为索引缺失引起性能的问题。
2 通过下面的语句来对索引和表使用时的I/O等待时间进行统计和计算,这里统计的是每次调用的延迟时间,通过历史数据比较可以发现某些索引或表在I/O上面的延迟变化,发现相关的索引使用中的衰减的现象。
select object_schema as database_name, object_name as table_name,index_name, sum_timer_wait/count_star/1000000000000 as sec from table_io_waits_summary_by_index_usage where SUM_TIMER_WAIT <> 0 ;
3 查询表的等待时间,通过查询数据获得平均每次访问表I/O的等待时间。
select object_schema as database_name,object_name as table_name,sum_timer_wait/count_star/1000000000000 as sec from table_io_waits_summary_by_table where count_star <> 0 ;
4 查看表中索引的个数(仅仅在MYSQL8 中作用,information_schema)
select it.name,ii.index_count from innodb_tables as it inner join (select table_id,count(*) as index_count from INNODB_INDEXES group by TABLE_ID) as ii on it.table_id = ii.table_id where it.name not like 'sy%' and it.name not like 'mysq%';
5 查询当前表访问过程中的锁的等待时间,这里通过查看平均每次的访问表的等待时间,发现某些时间较长的表,说明有缺少索引或索引有问题的可能性。
select object_schema as database_name,object_name as table_name,sum_timer_wait/count_star/1000000000000 as sec from table_lock_waits_summary_by_table where count_star <> 0 ;
6 查询95%中位数查询语句的耗时延迟,全表扫描等信息
select query,db,full_scan,exec_count,avg_latency,rows_sent,first_seen,last_seen from sys.statements_with_runtimes_in_95th_percentile where query like 'select%';
以上的信息都可以帮助DB 人员快速了解当前的MYSQL 数据库的索引的使用情况,并根据信息,进行更深入的分析和调整。