And*_*sch 2 sql-server optimization nonclustered-index
我们实现了一个 Google 风格的搜索,其中在前端触发去抖动后运行 SQL 查询。(我们知道 SQL 可能是错误的技术,但我在这里陷入了启动混乱。)查询:
SELECT
TOP(50) [Name], [Surname]
FROM
[dbo].[Clients]
WHERE
[Name] LIKE @SearchTerm + '%' OR
[Surname] LIKE @SearchTerm + '%'
Run Code Online (Sandbox Code Playgroud)
这是一个相当大的表,所以我在两列上添加了两个非聚集索引以帮助加快速度:
CREATE NONCLUSTERED INDEX [IX_Patients_Name] ON [dbo].[Clients]
(
[Name] ASC
)
INCLUDE([Surname]);
CREATE NONCLUSTERED INDEX [IX_Patients_Surname] ON [dbo].[Clients]
(
[Surname] ASC
)
INCLUDE([Name]);
Run Code Online (Sandbox Code Playgroud)
我的想法是 SQL 会在两列上进行索引查找,但查询优化器似乎决定使用索引扫描。
对于这个简单的用例,这可能不是一个真正的问题,但我们有更复杂的版本,具有多个连接等。
有什么方法可以优化此查询以使用搜索吗?
正如您在问题中提到的,这种 Google 风格的查询并不是 SQL Server 真正“擅长”的。Erik Darling在他的文章The Only Thing Thing Worse Than Optional Parameters... 中谈到了这个确切的查询反模式。
抛开这一切。
可以通过这种类型的查询自然地进行搜索,但如您所见,获得扫描更为常见。下面是 StackOverflow2010 示例数据库中的一个示例。
首先,我将创建这两个有用的索引:
CREATE NONCLUSTERED INDEX IX_DisplayName ON dbo.Users (DisplayName) INCLUDE ([Location]);
CREATE NONCLUSTERED INDEX IX_Location ON dbo.Users ([Location]) INCLUDE (DisplayName);
GO
Run Code Online (Sandbox Code Playgroud)
然后我将创建一个类似于您所拥有的程序:
CREATE OR ALTER PROCEDURE dbo.sp_Test
@SearchTerm nvarchar(100)
AS
BEGIN;
SELECT TOP (50)
DisplayName,
[Location]
FROM
dbo.Users
WHERE
DisplayName LIKE @SearchTerm + '%' OR
[Location] LIKE @SearchTerm + '%'
END;
GO
Run Code Online (Sandbox Code Playgroud)
如果我使用一个相当有选择性的参数运行该过程,我将最终得到一个索引联合计划。如果该参数的选择性较低,则改为使用对覆盖索引之一的扫描。
DBCC FREEPROCCACHE;
GO
EXEC dbo.sp_Test @SearchTerm = N'Josh';
GO
DBCC FREEPROCCACHE;
GO
EXEC dbo.sp_Test @SearchTerm = N'S';
GO
Run Code Online (Sandbox Code Playgroud)
请注意,即使您UNION直接将其编写为单独的查询也是如此。
如链接的帖子中所述,可靠地获取索引联合计划的一种方法是向FORCESEEK要联合的表添加提示。
如果我将 proc 更改为此,我不会对任何一个计划进行扫描:
CREATE OR ALTER PROCEDURE dbo.sp_Test
@SearchTerm nvarchar(100)
AS
BEGIN;
SELECT TOP (50)
DisplayName,
[Location]
FROM
dbo.Users WITH (FORCESEEK)
WHERE
DisplayName LIKE @SearchTerm + '%' OR
[Location] LIKE @SearchTerm + '%'
END;
GO
Run Code Online (Sandbox Code Playgroud)
查询的更大问题(无论如何在问题中进行了简化)是您在使用时TOP没有使用ORDER BY,这可能会根据使用的索引产生截然不同的搜索结果。确保您的真实查询具有ORDER BY,或者以某种方式解决了此问题。
| 归档时间: |
|
| 查看次数: |
134 次 |
| 最近记录: |