我们使用实体框架进行数据库访问,当我们“思考”LIKE语句时 - 它实际上生成了CHARINDEX的东西。所以,这里有2个简单的查询,在我简化它们以证明某个服务器上的一个点之后:
-- Runs about 2 seconds
SELECT * FROM LOCAddress WHERE Address1 LIKE '%1124%'
-- Runs about 16 seconds
SELECT * FROM LOCAddress WHERE ( CAST(CHARINDEX(LOWER(N'1124'), LOWER([Address1])) AS int)) = 1
表格现在包含大约100k条记录。地址1是VarChar(100)字段,没什么特别的。
这是两个并排的计划。没有任何意义,显示50%和50%,但执行时间像1:8
我在网上搜索,一般建议是使用CHARINDEX而不是LIKE。根据我们的经验,情况正好相反。我的问题是导致这种情况的原因以及如何在不更改代码的情况下修复它?
答案 0 :(得分:6)
我将回答我自己的问题,因为很难找到正确的答案,我被SQL Server 2012执行计划输出指出了问题。正如你在原始问题中看到的那样 - 表面上看起来一切都很好这是SQL Server 2008。
当我在2012年运行相同的查询时,我在CHARINDEX
查询时收到警告。问题是 - SQL Server必须进行类型转换。 Address1
为VarChar
,查询为N' 这是Unicode或NVarChar
。如果我更改此查询:
SELECT *
FROM LOCAddress
WHERE (CAST(CHARINDEX(LOWER('1124'), LOWER([Address1])) AS int))
然后与LIKE
查询运行相同。因此,由实体框架生成器引起的类型转换导致了这种可怕的性能损失。
答案 1 :(得分:4)
首先,正如您所看到的,两个查询都是相同的,并且都不能使用索引。 CHARINDEX和LIKE与通配符执行相同的操作。例如:%YourValue%。但是,当您使用像#Your; YourValue%'这样的通配符时,性能会有所不同。这里,LIKE运算符的执行速度可能比CHARINDEX快,因为它可能允许部分扫描索引。 现在,在您的情况下,两个查询都是相同的,但由于以下可能的原因,性能有所不同:
统计信息:SQL Server维护字符串列中子字符串的统计信息,这些字符串由LIKE运算符使用但不能完全用于CHARINDEX。在这种情况下,LIKE运算符将比CHARINDEX更快地工作。 您可以使用适当的表格提示force SQL Server to use index获取CHARINDEX
Ex:FROM LOCAddress WITH(INDEX(index_name))
阅读更多Here,其中包含" 字符串摘要统计数据"表示:
SQL Server 2008包含用于估算LIKE条件选择性的专利技术。它构建了一个统计摘要 字符列的子串频率分布(字符串 摘要)。这包括text,ntext,char,varchar类型的列, 和nvarchar。使用字符串摘要,SQL Server可以准确 估计模式可能具有的LIKE条件的选择性 任意组合的任意数量的通配符。