代码之家  ›  专栏  ›  技术社区  ›  Alex

除了索引之外的SQL Server优化建议

  •  1
  • Alex  · 技术社区  · 6 年前

    我正在处理一个sql查询,它需要许多自连接表来创建如下聚合函数。

    SELECT  
        tab1.foo, 
        tab1.bar, 
        tab1.baz, 
        tab1.bam/tab2.bam as bam_ratio, 
        RANK() OVER (PARTITION BY tab1.bar, tab1.baz ORDER BY tab1.foo DESC) RANK
    FROM 
        (SELECT 
             foo, 
             bar, 
             baz, 
             bam
         FROM 
             OPENDATASOURCE(server).dbo.table1
         WHERE 
             qux = 1 AND quux = 'A' AND corge = 2) tab1
    JOIN
        (SELECT 
             foo, 
             bar, 
             baz, 
             bam
         FROM 
             OPENDATASOURCE(server).dbo.table1
         WHERE 
             qux = 1 AND quux = 'B' AND corge = 2) tab2 ON tab1.bar = tab2.bar
                                                        AND tab1.baz = tab2.baz
                                                        AND tab1.foo = tab2.foo
    

    问题在于,这些表中的每一个表都只有数千万条记录,而列却很少。这就产生了一个独特的情况,索引并不能充分提高性能(上面的查询使用表1中的每一行)。

    我注意到,这些表调用往往只在一个或两个次要方面发生变化,例如示例中的qux,并且它们没有主键要求使用的行数多于必需的行数,这对索引没有帮助,而且似乎是多余的。

    有没有比简单的索引更能提高性能的方法?我愿意修改底层表并创建孤立表。

    2 回复  |  直到 6 年前
        1
  •  1
  •   S3S    6 年前

    您可以改进的一个性能问题是跨服务器连接。这在openrowset、链接服务器等中发生。

    最简单的缓解方法是将数据从远程数据源拉入临时表或临时表。这将在tempdb中本地存储数据。然后,加入临时表。sql server将自动为这些表创建统计信息,这将大大提高性能,而且数据是本地的,但是如果您愿意,还可以添加索引来加快连接速度。

        2
  •  0
  •   Bartosz X    6 年前

    在源服务器上需要此索引:

    CREATE NONCLUSTERED INDEX IX_NC_table1_bar_baz_INC_FILT ON dbo.table1(bar, baz)
    INCLUDE(foo, bam)
    WHERE qux = 1 AND quux = 'B' AND corge = 2;
    

    然后,您可以在其上创建一个索引视图,并在源框上创建一个带有rank()计算的sp。 一旦你拥有了所有这些,你只需要调用它来消耗你大部分预先计算好的数据+它的现金计划。

    更新:

    因此,在目标框上创建的sp应该是上述select语句的精确副本。您必须在目标服务器上创建它,以便创建和缓存sp执行计划,并使用您的统计信息进行更好的资源优化,从而获得更好的总体性能。 一旦你有了SP,就叫它:

    DECLARE @SP_SQL VARCHAR(128);
    SET @SP_SQL = 'EXEC [DB].[Schema].[SP_Name]'; --> from the target
    EXEC (@SP_SQL) AT [Target_Server];