如果未找到搜索词,SQL查询将继续运行很长时间

问题描述:

在我的Azure托管的ASP.NET Core站点中,我有一个用户表,并且实现了以下搜索:

In my Azure hosted ASP.NET Core site I have a table of users and I implemented search as follows:

    var inner = from user in db.Users
             select  new
             {
                 Name = user.Name,
                 Verified = user.Verified,
                 PhotoURL = user.PhotoURL,
                 UserID = user.Id,
                 Subdomain = user.Subdomain,
                 Deleted=user.Deleted,
                 AppearInSearch = user.AppearInSearch
             };
    return await inner.Where(u=>u.Name.Contains(name)&& !u.Deleted && u.AppearInSearch)
                                    .OrderByDescending(u => u.Verified)
                                    .Skip(page * recordsInPage)
                                    .Take(recordsInPage)
                                    .Select(u => new UserSearchResult()
                                    {
                                        Name = u.Name,
                                        Verified = u.Verified,
                                        PhotoURL = u.PhotoURL,
                                        UserID = u.UserID,
                                        Subdomain = u.Subdomain
                                    }).ToListAsync();

这将转换为类似于以下内容的SQL语句:

This translates to a SQL statement similar to the following:

SELECT [t].[Name], [t].[Verified],
       [t].[PhotoURL], [t].[Id], 
       [t].[Subdomain], [t].[Deleted], 
       [t].[AppearInSearch]  
FROM (      
        SELECT [user0].[Name], [user0].[Verified], 
               [user0].[PhotoURL], [user0].[Id], 
               [user0].[Subdomain], [user0].[Deleted], 
               [user0].[AppearInSearch]      
        FROM [AspNetUsers] AS [user0]
        WHERE (((CHARINDEX('khaled', [user0].[Name]) > 0) OR ('khaled' = N'')) 
          AND ([user0].[Deleted] = 0)) 
          AND ([user0].[AppearInSearch] = 1)      
        ORDER BY [user0].[Verified] DESC      
        OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY  ) AS [t]

如果搜索词在数据库中可用,则将在不到一秒钟的时间内获得结果. 但是,如果找不到,查询就会运行很长时间(我发现它达到48秒一次).

If the search term is available in the database, the result is obtained in less than a second. However, If it's not found the query runs for a very long time (I have seen it once reaching 48 seconds).

当我们将此功能发布到Internet时,这会极大地影响性能.

This greatly affects performance when we publish this feature to the internet.

您能提出一种解决此问题的方法吗?

Can you kindly suggest a way to solve this issue?

谢谢

更新:此问题在此处继续:显示sys时为空登录名.进程

Update: this issue is continued here: Empty Login Name When Showing sys.processes

SQL Server必须使用扫描来查找与.Contains子句匹配的行.没有办法解决这个问题.

SQL Server has to use a scan to find rows matching the .Contains clause. There is no way around this.

但是,如果我们减少SQL Server必须扫描的数据量,则会加快查询的速度.

However, if we reduce the amount of data that SQL server has to scan, we will speed up the query.

如果索引包含查询中需要返回的所有数据,则该索引为覆盖".

An index is "covering" if it contains all the data needed to be returned in a query.

CREATE INDEX IX_User_Name_filtered ON USER ([Verified], [Name]) 
INCLUDE ( [PhotoURL], [Id], [Subdomain], [Deleted], [AppearInSearch]  ) 
WHERE [AppearInSearch]=1 AND [Deleted]=0

此索引可能比原始表小很多,因此即使需要扫描,它也会更快.

This index is likely substantially smaller than the original table, so even if a scan is required, it will be quicker.

根据生成的计划,此索引可能是一个更好的选择.它不包括多余的列,并且还会更小.必须进行测试才能确定最佳选择.

Depending on the plan that is generated, this index may be a better choice. it doesn't include the extra columns and will be smaller still. Testing will be required to determine the best choice.

CREATE INDEX IX_User_Name_filtered ON USER ([Verified], [Name]) 
WHERE [AppearInSearch]=1 AND [Deleted]=0