[Analyze] 伯努利采样为什么在收集效率和资源使用上更有优势

https://docs.pingcap.com/zh/tidb/stable/statistics
这里面说的。
资源我还能理解,因为限制了采样的样本数。
效率提升是在哪?我看tikv代码collect_column_stats函数还是全表扫描啊
后面fast analyze好像也弃用了,是有啥别的替代方案么?

蓄水池采样的话,如果最终的采样集大小是 n,那么如果要保证正确性的话,每个 region 都要采 n 行上来,由 TiDB 再做一次蓄水池采样。
这样的话,如果要和现在伯努利采样一样默认采 10 万左右的数据上来的话,需要每个 region 都要返回 10 万行。那 TiDB 一个 region 通常也就 100 万行左右的数据,意味着实际的采样率达到了 10%,对于超大表来说其实是采了很多的冗余数据上来。
用伯努利的话就不存在这种问题了。实际上从蓄水池换到伯努利的同时,采样集也从默认的 10000 行扩大到了 100000 行左右。同时 Analyze 的速度反而会变快。

然后另一方面,原来因为采样集大小只有 10000,所以索引的统计信息只靠采样数据构造直方图的话,误差会偏大。在采样集扩大到 100000 之后,索引的直方图也可以通过采样来构造,这样就只要读 table kv 就好了,也省去了读 Index kv 的开销。(但是由于代码重构不干净,类似 index idx(a(10) 这种包含列前缀,或者虚拟列上的索引,仍然需要去读 Index kv,这部分也是提升收集效率和资源使用的一个待优化项)

因此整体上收集效率是提升了。

后面fast analyze好像也弃用了,是有啥别的替代方案么?

代替方案之后还会再测试。但是预期的话,会尽量不引入原来的 fast analyze 那样降低精度的方案,而是优先改善默认 Analyze 的速度(也就是优先考虑保证精度不下降的同时提升速度,而不是通过降低收集精度来提升速度)

2 个赞

谢谢回答~
之前索引直方图不是采样计算的吧,我记得是扫每个索引region,构造每个索引region的直方图
然后SQL层再merge这些直方图。因为扫索引是有序的。

我理解效率方面的优化主要有2点:
1)SQL层 merge的样本数变少了
2)索引也可以走采样了,而且大部分场景下,只需要扫一遍记录行regions,就能构造索引的各种统计信息

所以目前还是全表扫描 + 搭配一些提速手段(上面提到的2,以及不analyze某些类型的列)

有考虑过不扫全表来收集统计信息么?这样肯定会更快,但准确度确实不太好保证,甚至行数信息都不准了。

有考虑过不扫全表来收集统计信息么

目前还是没有倾向这边,主要是里面 NDV(不同值的个数)这个基于全量数据的 hash sketch based 算法(fmsektch, hyperloglog)所得到的,和通过采样得到的,精度上差距会非常明显。所以虽然很多其他的数据库是完全基于采样的,但是 TiDB 短期还不会考虑这边