6

我有一个 SQL 2008 R2 数据库,其中一个表中有大约 200 万行,并且在使用参数化 SQL 时正在努力解决特定查询的性能问题。

在表中,有一个包含名称的字段:

[PatientsName] nvarchar NULL,

该字段还有一个简单的索引:


CREATE NONCLUSTERED INDEX [IX_Study_PatientsName] ON [dbo].[Study] 
(
    [PatientsName] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [INDEXES]
GO

当我在管理工作室中执行此查询时,执行大约需要 4 秒:


declare @StudyPatientsName nvarchar(64)
set @StudyPatientsName= '%Jones%'

SELECT COUNT(*) FROM Study WHERE Study.PatientsName like @StudyPatientsName

但是,当我执行这个查询时:


SELECT COUNT(*) FROM Study WHERE Study.PatientsName like '%Jones%'

执行需要半秒多一点。

查看执行计划,没有参数化的查询使用上述索引进行索引扫描,这显然是有效的。参数化查询使用索引,但在索引上进行范围查找。

部分问题在于具有领先的通配符。当我删除前导通配符时,两个查询都会在几分之一秒内返回。不幸的是,我确实需要支持前导通配符。

我们有一个自制的 ORM,它会在问题出现的地方进行参数化查询。这些查询是根据用户的输入完成的,因此参数化查询对于避免诸如 SQL 注入攻击之类的事情是有意义的。我想知道是否有办法使参数化查询功能以及非参数化查询?

我已经进行了一些研究,寻找向查询优化器提供提示的不同方法,试图强制优化器在每个查询上重做查询计划,但还没有发现任何可以提高性能的方法。我试过这个查询:


SELECT COUNT(*) FROM Study WHERE Study.PatientsName like @StudyPatientsName
OPTION ( OPTIMIZE FOR (@StudyPatientsName = '%Jones%'))

在这个问题中提到了它作为解决方案,但它没有任何区别。

任何帮助,将不胜感激。

4

4 回答 4

4

您似乎想强制扫描。有一个FORCESEEK提示,但我看不到任何类似的FORCESCAN提示。不过应该这样做。

SELECT COUNT(*) 
FROM Study 
WHERE Study.PatientsName + '' like @StudyPatientsName

虽然也许您可以在您的数据上尝试以下操作,看看效果如何。

SELECT COUNT(*) 
FROM Study 
WHERE Study.PatientsName  like @StudyPatientsName
option (recompile)
于 2010-08-16T19:28:16.483 回答
3

我认为在这里提高性能的最佳机会是研究使用全文索引

于 2010-08-16T16:55:54.143 回答
0

如果一切都失败了,你可以试试

SELECT COUNT(*) FROM Study WITH(INDEX(0)) WHERE Study.PatientsName like @StudyPatientsName

也许你可以把它包装在一个 IF

IF substring(@StudyPatientsName, 1, 1) = '%'
    SELECT COUNT(*) FROM Study WITH(INDEX(0)) WHERE Study.PatientsName like @StudyPatientsName
ELSE
    SELECT COUNT(*) FROM Study WHERE Study.PatientsName like @StudyPatientsName

编辑:正如马丁指出的那样,对于这个特定的查询,这可能不是最好的方法,因为现有索引的索引扫描可能更快。不过,它可能适用于类似的情况。

于 2010-08-17T13:33:42.800 回答
0

我无法找到文档来验证这一点,但 IIRC,COUNT(*) 在 MS SQL 中进行全表扫描(而不是使用缓存值)。如果您针对不能为空和/或定义了索引的列运行它,我相信(同样,仍然找不到要确认的文档,所以我可能会在这里偏离基础)会更快。

当您将查询修改为以下内容时会发生什么:

SELECT COUNT(id) FROM Study WHERE Study.PatientsName Like @StudyPatientsName

或者

SELECT COUNT(PatientsName) FROM Study 
WHERE Study.PatientsName 
LIKE @StudyPatientsName
于 2010-08-16T17:05:05.330 回答