MariaDB百万级表:全列索引与子串索引选择咨询
核心差异分析与最优索引选型建议
针对你这张15-20百万行的MariaDB表,结合你大部分查询基于sku前6位分组、并搭配rate/region等维度统计的场景,我来拆解LEFT(sku,6)函数索引和全列sku索引的核心差异,以及适配你需求的方案:
1. 基数(Cardinality)的实际影响
- 函数索引的基数是sku前6位不同值的数量,全列索引则是整个12位sku的不同值数量。显然全列索引基数更高,但你的查询只聚焦前6位,所以函数索引的基数完全能满足分组需求——只要前6位的区分度足够(比如每个前6位对应几十到上百个完整sku),这个基数就足以让优化器选择走索引而非全表扫描,不会成为性能瓶颈。
- 举个实际例子:如果你的sku前6位平均对应20个不同完整sku,那函数索引基数是全列的1/20,但对于分组统计前6位的场景,这个基数已经足够支撑高效的索引遍历。
2. 查询性能的直接对比
- 适配你的核心场景:函数索引是为
LEFT(sku,6)这个逻辑量身定制的,当你写GROUP BY LEFT(sku,6)或者WHERE LEFT(sku,6) = 'xxxxxx'时,优化器可以直接利用索引定位数据,不需要对每条记录计算子串,性能更直接高效。 - 全列索引的局限:如果查询中用到
LEFT(sku,6),优化器通常不会走全列索引(除非有特殊的隐式转换,但大概率不会),它需要遍历全列索引后再计算每个sku的前6位才能匹配,这会退化为索引扫描甚至全表扫描,性能远不如函数索引。 - 例外情况:如果你的业务偶尔需要基于完整sku的精确过滤,全列索引能覆盖这种场景,但根据你的描述这类场景很少,没必要为小众需求额外付出索引维护成本。
3. 索引维护与存储的隐性差异
- 函数索引的每条记录只存储前6位字符串,大小约为全列索引的一半。虽然你说存储空间不成问题,但更小的索引意味着内存缓存命中率更高、IO操作更少,在百万级大表场景下,这会带来明显的性能提升(尤其是查询高峰时)。
- 大表的索引维护成本:全列索引在插入、更新sku字段时,需要写入更长的字符串,IO开销比函数索引大,长期来看会影响写入性能。
4. 多维度查询的进阶优化
你提到多数查询会结合rate、region等维度做统计,比如SELECT LEFT(sku,6), COUNT(*) FROM your_table WHERE rate = 0.8 AND region = 'CN' GROUP BY LEFT(sku,6)。这种情况下,复合函数索引会比单一索引更高效:
- 推荐创建复合索引:
(rate, region, LEFT(sku,6)),或者如果LEFT(sku,6)的区分度更高,也可以调整为(LEFT(sku,6), rate, region)——具体顺序取决于你的过滤条件选择性:如果rate+region能筛选掉80%以上的数据,就把它们放在前面;如果前6位的分组区分度更高,就把函数列放在首位。 - 这类复合索引可以直接覆盖过滤+分组的需求,避免回表查询,性能会比单一索引提升一个档次。
最终选型建议
- 优先选择**
LEFT(sku,6)函数索引**,它完全适配你的核心查询场景,性能更优、索引更小、维护成本更低。 - 结合多维度统计需求,进一步优化为复合函数索引,把常用的过滤字段和
LEFT(sku,6)组合起来,最大化索引效率。 - 除非有频繁的完整sku过滤需求,否则不需要创建全列sku索引,避免不必要的资源消耗。
内容的提问来源于stack exchange,提问作者cadre
相关产品推荐
相关产品推荐

