如果找不到搜索词,SQL Query将继续运行很长时间

时间:2017-06-02 16:37:58

标签: sql sql-server linq linq-to-sql asp.net-core

在我的Azure托管的ASP.NET核心站点中,我有一个用户表,我按如下方式实现了搜索:

    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语句:

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秒)。

当我们将此功能发布到互联网时,这会极大地影响性能。

您能否提出解决此问题的方法?

谢谢

更新:此问题在此处继续:Empty Login Name When Showing sys.processes

2 个答案:

答案 0 :(得分:0)

您已经可以像这样简化查询;):

int start=page * recordsInPage;

var inner = (from user in db.Users
            where user.Name.Contains(name) && !user.Deleted && user.AppearInSearch
            orderby user.Verified descending
            select  new
                   {
                     Name = user.Name,
                     Verified = user.Verified,
                     PhotoURL = user.PhotoURL,
                     UserID = user.Id,
                     Subdomain = user.Subdomain,
                     Deleted=user.Deleted,
                     AppearInSearch = user.AppearInSearch
                   }
             ).Skip(start).Take(recordsInPage);

return await inner.ToListAsync();

如果遇到性能问题,请尝试使用SQL创建存储过程并将其与实体框架一起使用。

答案 1 :(得分:0)

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

但是,如果我们减少SQL服务器必须扫描的数据量,我们将加快查询速度。

覆盖过滤指数

索引是"覆盖"如果它包含查询中需要返回的所有数据。

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

此索引可能比原始表格小得多,因此即使需要扫描,也会更快。

根据生成的计划,此索引可能是更好的选择。它不包括额外的列,并且会更小。需要进行测试以确定最佳选择。

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