我有一张包含大约100万条记录的表(运行SQL Server 2008 Web)。我有一个搜索例程,试图匹配产品代码和产品描述。 但是在某些情况下它很慢。下面是(cut-down)sql语句:
WITH AllProducts AS (
SELECT p.*, Row_Number() OVER (ORDER BY ProductId) AS RowNumber
FROM Product AS p
WHERE p.IsEnabled=1 AND
(
p.BaseSku = 'KPK-3020QWC-C' -- this on its own is fast
OR
CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"') -- and this on its own is fast, but not both
)
) SELECT * FROM AllProducts
WHERE RowNumber BETWEEN 1 AND 20;
请注意,如果我只是在[p.BaseSku ='KPK-3020QWC-C']或[CONTAINS(p.FreeTextStrings,'“KPK-3020QWC *”')上单独(但不是两者)比较它的瞬间。如果我将它们进行比较,则需要很长时间(几分钟) - 并且只返回一行。
IsEnabled和BaseSku被编入索引,FreeTextStrings被FTS索引。
我记得这一切都很好。
有人可以对此有所了解并提出一些解决方案吗?
执行计划文件可在此处获取:http://wiki.webgear.co.nz/GetFile.aspx?File=Temp%5cSearch%20Test.sqlplan.zip
答案 0 :(得分:10)
or
在SQL Server上出了名的慢。至少可以说,这是加重的。
尝试使用union
WITH AllProducts AS (
select *, Row_Number() OVER (ORDER BY ProductId) AS RowNumber
from (
SELECT p.*
FROM Product AS p
WHERE p.IsEnabled=1 AND
p.BaseSku = 'KPK-3020QWC-C'
UNION
SELECT p.*
FROM Product AS p
WHERE p.IsEnabled=1 AND
CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"')
)
) SELECT * FROM AllProducts
WHERE RowNumber BETWEEN 1 AND 20;
答案 1 :(得分:1)
这似乎运作良好:
WITH AllProducts AS (
SELECT p.*, Row_Number() OVER (ORDER BY ProductId) AS RowNumber
FROM Product AS p
WHERE p.IsEnabled=1 AND
(
CONTAINS(p.BaseSku, 'KPK-3020QWC-C') /* instead of p.BaseSku = 'KPK-3020QWC-C' */
OR
CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"')
)
) SELECT * FROM AllProducts
WHERE RowNumber BETWEEN 1 AND 20;
(我已经有BaseSku FTS索引)
答案 2 :(得分:0)
Make sure all necessary indexes are in place.
我在其中一个查询中遇到了or
子句的相同问题,并且使用INCLUDE列创建了一个NONCLUSTERED INDEX来修复性能。
经过进一步测试后,索引的 INCLUDE列部分确实解决了性能问题。以下是我为确定问题以及如何解决问题所做的工作:
使用执行计划来帮助您创建缺失的索引:
如果没有索引,那么当它应该在几毫秒内运行时,查询需要2+分钟。因此,我在SSMS中使用和不使用or
子句来比较查询的执行计划,并且我不需要做什么(主要是由于我对执行计划缺乏了解)。
但是如果你在绿色文本中查看执行计划,SSMS可能会告诉你创建一个非聚集索引。嗯......值得一试。所以我创建了索引并解决了问题!您可以右键单击"创建索引"查询并选择"缺少索引详细信息..."。这将打开一个新选项卡,其中包含您要运行的完整查询。只要给它一个名字。