sql - 在需要集合操作的 SQL Server 数据库中,如何设计更高的可扩展性?

标签 sql sql-server performance scale

想象一个电影应用程序,它根据这个非常简单的算法向用户推荐下一部电影:

  • 电影应该是新用户
  • 用户尚未将电影标记为“不感兴趣”

  • 这是 SQL Server 数据库的简单设计:
    Movies:
        Id bigint
        Name nvarchar(100)
    
    SeenMovies:
        Id bigint
        UserId bigint
        MovieId bigint
    
    NotInterestedFlags:
        Id bigint
        UserId bigint
        MovieId bigint
    

    为了获取下一部电影,我们运行以下查询:
    select top 1 *
    from Movies 
    where Id not in 
    (
        select MovieId 
        from SeenMovies 
        where UserId = 89283
    )
    and Id not in 
    (
        select MovieId 
        from NotInterestedFlags
        where UserId = 89283
    )
    

    随着应用程序的使用和数据的增加,这种设计变得越来越慢。
    那么对于一个拥有 10 万部电影和超过 1000 万客户的虚构数据库,如何改变这种设计使其水平扩展?

    最佳答案

    以下是我推荐的代码。

    我假设 SeenMovies 和 NotInterestedFlags 在 UserId 上聚集,或者至少索引。并且 Movies 聚集在 MovieId 上。如果没有,首先添加此类索引。

    我当然看不出有任何理由为什么每个查询的性能会很差,因为一​​旦我们将查询限制在特定用户,SeenMovies 和 NotInterestedFlags 最多应该只有一个该用户各有几千行。

    SELECT TOP 1
        Movies.*
    
    FROM
        Users
    
    CROSS JOIN
        Movies
    
    WHERE 
        NOT EXISTS
        (
            SELECT NULL
            FROM SeenMovies
            WHERE 
                SeenMovies.UserId = Users.Id
                AND
                SeenMovies.MovieId = Movies.Id 
        )
        AND 
        NOT EXISTS
        (
            SELECT NULL
            FROM NotInterestedFlags
            WHERE 
                NotInterestedFlags.UserId = Users.Id
                AND
                NotInterestedFlags.MovieId = Movies.Id 
        )
        AND
        Users.Id = 89283
    

    如果即使使用适当的索引这仍然表现不佳,我只能想象第一个可能是第一个 UNION在该 UserId 的 SeenMovies 和 NotInterestedFlags 中添加 MovieId 条目,然后 EXCEPT将这些用于电影,可能会提供更好的性能。

    另一方面,如果问题是系统的整体性能在许多用户的负载下下降,您可能需要考虑为每个用户预先准备一个列表,用于未看过和未列入黑名单的电影,从您查询的 TOP 1 .

    然后,当用户观看电影或将其列入黑名单(或添加新电影)时,此新表与单独的 SeenMovies 和 NotInterestedFlags 表同时被修改。

    同样,如果这对性能没有足够的帮助,那么您必须考虑实现每日批处理作业,这可能会预先准备一份列表,其中包含每个用户的 10 部未看过且未列入黑名单的电影,然后该表是一次查询并提供给用户。

    不过我坦率地认为,如果您有可能拥有 1000 万用户,那么您可能会聘请一位专家来编写代码或评估现有系统。

    关于sql - 在需要集合操作的 SQL Server 数据库中,如何设计更高的可扩展性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44543923/

    相关文章:

    sql - 在oracle sql上使用CASE条件

    sql-server - 在sql查询中使用bigint时得到错误的结果

    javascript - node.js mssql javascript方法第二次调用从数据库打印未定义的数据

    sql - 如何优化 PostgreSQL COUNT GROUP BY 查询?

    Perl:计算大量数据的相关系数时的编程效率

    php - jqGrid 集成工具栏搜索不起作用

    sql - PostgreSQL:可以创建具有 TYPE 的函数并在之后修改 TYPE

    SQL Server 2008事务复制 'Missing end comment mark ' */''

    SQL 服务器 : nesting elements with FOR XML PATH

    Cuda中的凸多边形算法?