使用 group by 和 like 语句时如何让 SQL 使用 where 条件
Posted
技术标签:
【中文标题】使用 group by 和 like 语句时如何让 SQL 使用 where 条件【英文标题】:How to get SQL to use where criteria when using group by and like statements 【发布时间】:2011-08-10 17:35:35 【问题描述】:我有一个包含分组依据的 SQL 视图。我正在尝试使用点赞从视图中进行选择。我选择的列已编入索引,但 SQL 坚持创建一个包含表中所有行的临时表,然后根据 where 条件进行过滤。 (慢)如何让它先过滤?
示例:
查看定义:
SELECT ListCode, SUM(CASE
WHEN ListStatus = 'A' THEN 1
ELSE 0
END) Active
FROM ListParticipation
GROUP BY ListCode
选择:
SELECT *
FROM ListParticipationView
WHERE ListCode like '%ReallyCoolList%'
顺便说一句,如果我使用没有开头通配符的类似条件,SQL 计划确实会显示在组汇总之前发生的过滤。
【问题讨论】:
我最好的猜测是,您真正的解决方案是将列表传递给LIKE
语句,因为我假设它是Many-to-Many Relationship。
【参考方案1】:
您的条件不是 SARGable,即它不能使用索引。
在比较字符串的开头使用LIKE
和%
可以保证表扫描。 SQL 必须检查每一行中的整个字段以评估匹配项。
如果您的ListCode
是一个很长的字符串,也许您应该将其设为一个int,即查找表中的PK
。然后你可以评估:
WHERE Listcode IN (1, 3, 4, 6)
并使用索引。
【讨论】:
【参考方案2】:它没有首先过滤,因为开始的通配符阻止了索引被使用。基本上,它必须搜索 整个 字符串 - 所以它仍然必须搜索 每一行,因为 char
或 varchar
上的索引通常从第一个字符...这大致相当于想知道为什么不使用多列索引,而您的选择标准仅基于第二列或第三列,而不是第一列。
如果您有重复 ListCode
s(显然是这种情况),请考虑将它们提取到自己的表中,然后将新表的 id 作为 listCodeId
放在 ListParticipation
表中(并替换索引)。如果你有一个足够聪明的优化器,它会在他们的表中找到所有与给定通配符字符串匹配的listCode
s(应该是唯一的,所以请有一个唯一的约束),然后用它来查询 fk 索引在listCodeId
。性能应该更高。
【讨论】:
我实际上对索引扫描没问题。我认为我的困惑在于,如果我执行以下操作: SELECT ListCode, SUM(CASE WHEN ListStatus = 'A' THEN 1 ELSE 0 END) Active FROM ListParticipation WHERE ListCode like '%ReallyCoolList%' GROUP BY ListCode 这个性能很多更好的。它首先进行全表扫描,仅获取需要汇总的行,然后进行分组。不知道我需要做些什么不同的事情才能让视图使用相同的计划。 您不是在进行索引扫描,而是在进行表扫描。而且我怀疑您的 RDBMS 没有解决where
谓词与视图中的分组列之间的相关性 - 将其作为一个查询来解决这个问题。不过,我不知道他们中有多少可以解决这个问题。不过,仍然建议将ListCode
s 拉到他们自己的桌子上。【参考方案3】:
我知道您已经了解了为什么视图通常是一个坏主意。如果他们调用其他视图,情况会变得更糟。如果直接访问表的 SQL 语句更快,请使用它。但不要将 where 子句与以通配符作为第一个字符的 like 语句一起使用。对一次性查询以外的任何内容执行此操作表明您需要使用不同的技术,例如:
-
您需要修复设计
或
您需要使用全文索引
如果您在一个列中存储诸如“test、mytest、另一个愚蠢的测试”之类的数据,并使用 like 子句查找“mytest”的所有值,那么您需要对表进行规范化并正确存储数据。
如果您的用户正在搜索他们可能不知道确切名称的字词(比如一个较长的正式机场名称,例如“罗纳德里根国家机场”,并且搜索可能是“国家机场”),那么请改用全文索引.
如果您无缘无故将 % 放在前面,请停止这样做。
【讨论】:
以上是关于使用 group by 和 like 语句时如何让 SQL 使用 where 条件的主要内容,如果未能解决你的问题,请参考以下文章
用group by语句时,字段很多并且数据量也很大的情况如何解决?