搜索查询不处理大量用户

时间:2017-06-01 13:49:15

标签: sql sql-server entity-framework asp.net-core azure-sql-database

我们有一个asp.net核心网站,用于处理用户搜索,如下所示:

    public async Task<ICollection<UserSearchResult>> SearchForUser(string name, int page)
    {
        return await db.ApplicationUsers.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.Id,
                                            Subdomain = u.Subdomain
                                        }).ToListAsync();
    }

查询转换为类似于以下内容的内容:

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

在客户端,我们使用typeahead和bloodhound如下:

    engine = new Bloodhound({
        identify: function (user) {
            return user.UserID;
        },
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
        dupDetector: function (a, b) { return a.UserID === b.UserID; },
        remote: {
            cache: false,
            url: '/account/Search?name=%QUERY&page=0',
            wildcard: '%QUERY'
        }
    });

我们按如下方式配置typeahead:

    $('#demo-input').typeahead(
    {
        hint: $('.Typeahead-hint'),
        menu: $('.Typeahead-menu'),
        minLength: 3,
        classNames:
        {
            open: 'is-open',
            empty: 'is-empty',
            cursor: 'is-active',
            suggestion: 'Typeahead-suggestion',
            selectable: 'Typeahead-selectable'
        }
    },
    {
        source: engineWithDefaults,
        displayKey: 'name',
        templates:
        {
            suggestion: template,
            empty: empty,
            footer: all
        },
        limit: 5
    })

搜索只能在localhost上找到,并且查询作为sql查询运行良好。 我还创建了一个已验证的索引,并将速度降低到1秒或更短。

我们的网站拥有数百万注册用户,问题是只要我们为所有用户提供搜索,Azure上的DTU百分比就会达到100%并且查询会超时。 我们还有一个redis缓存来加速类似的查询,但这对我们没有帮助解决这个问题。

感谢您的支持:)

1 个答案:

答案 0 :(得分:0)

它很可能是u.Name.Contains(name),即CHARINDEX('khaled', [u0].[Name]) > 0,它必须扫描整个表格,或者最好是扫描索引。这将是缓慢的,你可以做的不多。

如果您对deletedappearInSearch有较大的偏见,则可能会使用条件索引,但这些类型的搜索速度非常慢。你需要一些特殊的结构来实现这个目的。