多连接数百万条记录的优化查询需要建议

Posted

技术标签:

【中文标题】多连接数百万条记录的优化查询需要建议【英文标题】:Need suggestion on optimization query of multiple million of records with multiple joins 【发布时间】:2017-10-21 11:15:01 【问题描述】:

如何优化此查询,因为 EXT 表每个包含大约 150 万条记录。我还有其他联接,但它们的记录相对少于 50 条。 两个 EXT 表都使用默认设置设置身份,并且是 P

SELECT *
FROM (
  SELECT
    ROW_NUMBER() OVER(ORDER BY ID ASC) AS RowNumber
    , *
  FROM History
    LEFT JOIN FlattenExt1 
      ON History.ID = FlattenExt1.ExtID
    LEFT JOIN FlattenExt2 
      ON History.ID = FlattenExt2.ExtId
  ) as final
where final.RowNumber BETWEEN (@PageIndex -1) * @PageSize + 1
                          AND (((@PageIndex -1) * @PageSize + 1) + @PageSize) - 1
order by final.rownumber

【问题讨论】:

使用Paste The Plan @ brentozar.com 分享您的执行计划,以下是说明:How to Use Paste the Plan。 如前所述共享您的表 DDL 和执行计划。 @artashes Khachatryan 实际上,这只是一段代码,仅在左连接方面需要优化的地方。还有其他内部连接,无论如何这都是必要的,但我在这里没有提到。 @MonkeyD.luffy 我们需要查看包含在此查询中的表的创建语句以帮助您。 【参考方案1】:

从可见的情况来看,我认为优化器的问题是运气知道左连接是否重复 HISTORY.ID 值,从而影响 ROW_NUMBER。 如果左连接条件都具有每个历史记录行 0-1 行的连接限制,则仅对历史记录执行 ROW_NUMBER,获取 id,然后加入

DECLARE @page INT = 150 , @rows INT = 10
;WITH 
data AS (SELECT ID  FROM History)
,rows (page, pages, rows) AS ( SELECT @page, CEILING(CAST(COUNT(*) AS float)/@page), COUNT(*) FROM data )
SELECT * FROM history INNER JOIN 
    (SELECT TOP (@rows) rowNumber,page, pages, rows,ID 
          FROM ( SELECT row_number() OVER (ORDER BY ID  ASC ) rowNumber, * FROM rows, data ) pagination
          WHERE rowNumber > (@page-1) * @rows
          order by rowNumber
    )historypageids ON history.ID = historypageids
LEFT JOIN FlattenExt1 ON History.ID = FlattenExt1.ExtID
LEFT JOIN FlattenExt2 ON History.ID = FlattenExt2.ExtId

【讨论】:

这个建议让我大大优化了查询时间,谢谢【参考方案2】:

这回答了问题的原始版本(通用 SQL Server)。

以下仅适用于 SQL Server 2012+。

如果您不需要 row_number() 值,我建议:

 SELECT . . .
 FROM History h LEFT JOIN
      FlattenExt1 f1
      ON h.ID = f1.ExtID LEFT JOIN
      FlattenExt2 f2
      ON h.ID = f2.ExtId                                                           
 ORDER BY h.ID
 OFFSET (@PageIndex -1) * @PageSize + 1 
 FETCH NEXT @PageSize ROWS;

这应该能够利用History(ID)FlattenExt1(ExtId)FlattenExt2(ExtId) 上的索引。

【讨论】:

我只能使用 SQL2008R – @MonkeyD.luffy,我在您的问题中添加了特定于版本的标签。

以上是关于多连接数百万条记录的优化查询需要建议的主要内容,如果未能解决你的问题,请参考以下文章

具有数百万条记录的 2 个数据帧之间的 Pyspark 交叉连接

优化返回大量记录的查询,避免数百个连接。这是一个聪明的解决方案吗?

优化插入数百万条记录,MySQL 和 PHP

在具有数百万条记录的 2 个表上加入更快

数百万条记录的增量更新,索引与连接

与 laravel 在处理数百万条记录时使用块的普通查询构建器相比,Laravel Eloquents 和使用块是不是更慢?