未对MySQL SET列使用索引

lymgl2op  于 2022-10-31  发布在  Mysql
关注(0)|答案(2)|浏览(152)

我有一个大型数据表,其中包含按日期和3个独立条件的详细信息,每个条件大约有12个离散值。也就是说,表中的每个条件字段都定义为12个值的ENUM。用户按日期和这三个条件的任何筛选提取汇总数据,包括根本不提取汇总数据。要使单个条件查找高效,需要3个单独的索引(date,CriteriaA)、(date,CriteriaB)、(date,CriteriaC)。如果您要根据3个(date,A,B,C)、(date,A,C)、(date,B,C)、(date,C)中的任何一个进行查找,则可以使用4个索引。
为了提高查找效率,我构建了一个SET列,其中包含来自3个条件的所有36个值。所有条件中的值都是唯一的,并且没有一个值是其他值的子集。我向该集合添加了一个索引(date,set_col)。但是,使用集合查找对此表进行的查询无法利用索引。FIND_IN_SET('Value',set_col)set_col LIKE '%Value%' norset_col & [pos. in set]触发索引(根据解释和整体结果集返回速度)。
是否有索引SET列的技巧?
我尝试了如下查询

Select Date, count(*) 
FROM tbl 
where DATE between [Start] and [End] 
and FIND_IN_SET('Value',set_col) 
group by Date

我希望它的运行速度与对单个条件列(具有索引)进行查找的速度一样快。但相反,当只存在对DATE的索引时,它的运行速度一样快。根据Explain处理的行数相同。

ddrv8njm

ddrv8njm1#

不可能为任意查询索引SET列。
SET类型基本上是一个位字段,为您的集合定义的每个值都设置了一个位。您可以在这样的位字段中搜索 * 特定 * 位模式,也可以搜索特定位模式的范围或不等式等。但是,搜索在位字段中设置了一个特定位的行将是不可索引的。
FIND_IN_SET()实际上是在位域中搜索一个特定的位集。它不会为这个 predicate 使用索引。最好的优化方法是使用一个索引,根据date上的另一个搜索项缩小所检查的行。然后在与date范围匹配的行中,将逐行应用FIND_IN_SET()。
这与搜索子字符串的问题是一样的。下面的 predicate 不会在列上使用索引:

SELECT ... WHERE SUBSTRING(mytext, 5, 8) = 'word'

SELECT ... WHERE LOCATE(mytext, 'word') > 0

SELECT ... WHERE mytext LIKE '%word%'

传统的数据索引是从字符串的 start 开始按字母顺序排列的,而不是从字符串中间的某个任意点开始。这就是为什么全文索引被创建为对整个字符串值的简单B树索引的替代方案。但是没有针对位字段的特殊索引类型。
我不认为SET数据类型对您的情况有帮助。您应该使用列排列的多列索引。

1rhkuytd

1rhkuytd2#

返回3个ENUM。然后

INDEX(A, date),
INDEX(B, date),
INDEX(C, date)

这些应该对查询有很大帮助,例如

WHERE A = 'foo' AND date BETWEEN...

也对

WHERE A = 'foo' AND date BETWEEN...
  AND B = 'bar'

如果您还将有没有A/B/C的查询,则添加

INDEX(date)

注意:当使用“范围”时,INDEX(date, A)并不比INDEX(date)更好,也就是说,我建议 * 反对 * 你提到的索引。
FIND_IN_SET()与几乎所有其它函数调用一样,不是sargable.但是,enum=const是可优化搜索得,因为它是作为简单整数实现得.
你没提到

WHERE A IN ('x', 'y') AND ...

这实际上是不可索引的。然而,我的建议总比没有好。

相关问题