统计信息是经常遇到的问题,官方文档和TUG上已有较多关于统计信息的文章,本文对遇到的统计信息问题在分析、测试的基础上进行总结。
1、 stats_meta如何更新?
Stats_meta主要记录表、分区的记录DML数量,当stats-lease大于0时(默认为3秒,当为0时则关闭该更新功能),每隔20*statsLease 会更新stats_meta信息(TiSpark需要开启enableUpdateTableStatistics),对于执行过统计信息收集的表auto-analyze依据modify_count/row_count和tidb_auto_analyze_ratio决定是否执行。对于不同的操作modify_count/row_count 2个列数值处理方式不同:
- Insert: 增加modify_count,增加row_count。
- Delete: 增加modify_count,减少row_count。
- Update: 增加modify_count,row_count不变。
2、 Auto-analyze是谁执行的?
同DDL一样,auto-analyze会选出一个tidb server作为stats owner节点,由stats owner节点执行,成为owner后tidb.log会有如下信息, 并且auto-analyze的相关日志会写入owner 的tidb.log,stats owner一般和ddl owner为同一tidb,可通过 TIDB_IS_DDL_OWNER()查询当前连接到的tidb server是否为owner, 或使用curl http://tidb_ip:10080/info/all 查看哪个tidb 为Owner。
[2022/03/21 17:16:09.697 +08:00] [INFO] [manager.go:325] ["get owner"] ["owner info"="[stats] /tidb/stats/owner ownerManager 23b398c8-b69c-4b3e-aa88-50bf14dc0276"] [ownerID=23b398c8-b69c-4b3e-aa88-50bf14dc0276] |
3、 Auto-anlyze什么时候执行?
Tidb启动时会启动一个goroutine每隔statlease(3秒)时间执行auto-analyze检查是否有满足条件的表需要收集统计信息:
(1) 前提条件:stats-lease参数>0,开启auto-analyze(performance.run-auto-analyze参数)且在tidb_auto_analyze_start_time/end_time变量指定的时间内。
(2) 未analyze过的表:表中数据row_count≥1000条,且在20*statsLease 时间内没有DML执行。
(3) 已做过analyze的表:表中数据row_count≥1000条,当即当某个表的修改行数与总行数的比值(modify_count/row_count)> tidb_auto_analyze_ratio后。
(4) 新建索引后,对于5.3.0、5.2.2之前版本,新建索引后无论是否位于规定的analyze-time时间内都会触发auto-analyze。
["[stats] auto analyze triggered"] [sql="analyze table `test`.`ta`"] [reason="table unanalyzed, time since last updated 1m0.029623177s"] |
4、 auto-analyze和manual analyze有什么区别?
在执行统计信息收集时auto-analyze和manual analyze都执行analyze SQL,不同的是auot-analyze是内部session执行,对于内部session tidb有资源限制,能提升统计信息收集效率的参数值都设置为1,因此会导致auto-anlyze比manual analyze执行慢。
5、 Auto-analzye失败原因?
比较常见的auto-analyze失败原因是执行时间过长超过了GC safepoint,在计算safepoint时,会从pd获取当前时间now并减去24小时(max-txn-time-use)作为startTSLowerLimit,,然后获取所有活动事务的processlist的startts, 以 min(startTSLowerLimit,starts)为safepoint时间。 触发auto analyze 的内部 session 并不会被统计在 processlist 中(show processlist也不会展示),这样就出现 safepoint > auto analyze 事务的 start_ts 的情况,导致 auto analyze 失败。6.0版本后会进行改进。
[tikv:9006]GC life time is shorter than transaction duration, transaction starts at 2021-11-17 14:09:54.756 +0800 CST, GC safe point is 2021-11-17 14:11:54.755 +0800 CST |
6、 为什么无法看到更多Analyze历史记录?
Analyze table的历史记录可通过show analyze status命令查看,目前存在以下问题:
(1) 只能查看近20条记录,且记录信息在内存中,tidb server重启后信息丢失。
(2) 只能看到本tidb server 内执行的分析记录,无法看到全局信息。
根据https://github.com/pingcap/tidb/pull/32215描述后续版本中会将分析记录到 mysql.analyze_jobs,show analyze status可以查看近30条记录
7、 直方图里为什么看不到列信息?
show stats_buckets/stats_histograms 只会显示加载到内存中的统计信息。系统启动时会将表、索引级统计信息加载到stats cache内,因此表和索引级的统计信息是常驻内存的,每隔 stats-lease 时间,TiDB 会检查统计信息是否有更新,有的话被加载到内。
对于列的统计信息,其数据量较大占用的的内存较多,当有查询条件涉及到该列时,tidb 才会将该列的统计信息加载到内存中,每隔 stats-lease 时间,会检查是否有列统计信息需要备加载到内存。
5.4版本中推出统计信息同步加载实验功能,在执行SQL时同步将直方图、TopN、CMSketch 等信息加载,通过参数tidb_stats_load_sync_wait控制。
8、 tidb_analyze_version=2时oom候如何处理?
tidb_analyze_version是5.1.0版本引入的实验特性,在5.1、5.2版本被设置成了默认值(一个小小失误),所以经常在这2个版本看到系统甚至在没有什么查询的情况下tidb server内存增长或oom,是由于在version=2时收集统计信息后channle未关闭的bug造成(5.3版本修复)。可按如下步骤处理:
(1) 设置全局变量 tidb_analyze_version 为 1
set @@global.tidb_analyze_version = 1;
(2) 使用如下的 SQL 生成 DROP STATS 的语句并执行。
Tidb在收集统计信息是如果表内已经有统计信息则按表内记录的统计信息version来收集,因此需要删除现有统计信息才能使version=1生效。
select distinct(concat(‘DROP STATS ‘,table_schema, ‘.’, table_name,’;’)) from information_schema.tables, mysql.stats_histograms where stats_ver = 2 and table_id = tidb_table_id ;
(3) 手动或等待 auto-analyze 重新收集
9、 Feedback有什么作用?
Feedback是2.1版本中引入的功能,根据SQL实际执行时统计的行数等信息和生成执行计划的预估信息做比对,根据对比的差异去更新统计新(stats-lease=0则不更新统计信息),主要包括直方图和CM-Sketch,其主要目的是在未能及时收集统计信息的情况下,能够在SQL执行后使用最准确的数据来更新统计信息。
在 v5.0 版本之前,TiDB 会以 feedback-probability 的概率收集反馈信息,由于该功能尚不完善,有可能造成panic/oom,因此5.0版本前建议手动关闭。 对于 v5.0 版本该功能默认关闭,不建议开启此功能。
10、 analyze SQL中选项的默认值是多少?
Analyze语句可以使用选项控制每类统计信息采样时使用的值:
WITH num BUCKETS 用于指定生成直方图的桶数量上限,默认256,上限1024。
WITH num TOPN 用于指定生成 TOPN 数目的上限,默认20,上限1024。
WITH num CMSKETCH DEPTH 用于指定 CM Sketch 的深度,默认5。
WITH num CMSKETCH WIDTH 用于指定 CM Sketch 的宽度,默认2048。
WITH num SAMPLES 用于指定采样的数目,默认10000,上限500000 (即使指定了仍需扫描所有行 https://asktug.com/t/topic/243035/13)。
WITH FLOAT_NUM SAMPLERATE 用于指定采样率,范围(0,1] (5.3版本后)。
--------------------------------------------------------------------------------------------------------
2023.5.8更新:
6.5.0版本后 auto analyze增加了 变量 tidb_auto_build_stats_concurrency
控制autoanlyze的并行度。tidb_auto_analyze_partition_batch_size
控制分区表autoanalyze时同时进行收集的分区个数。