需要优化 mssql 查询以获得最快的速度

Posted

技术标签:

【中文标题】需要优化 mssql 查询以获得最快的速度【英文标题】:Need to optimize mssql query for fastest speed 【发布时间】:2014-08-06 09:52:56 【问题描述】:

请帮助我对以下查询进行优化。 “#oz”临时表有 16000 行。现在这个查询运行了大约 14 秒。

DOWNLOAD QUERY WITH DATA

create table #oz (
    id int, from_sto_move bit, product_id int, [date] datetime,
    qty_orlogo decimal(30, 10), qty_zarlaga decimal(30, 10), cost_prev decimal(30, 10)
)

print 'Query started on: ' + CONVERT(nvarchar(30), GETDATE(), 126)
select
    oz1.product_id,
    oz1.id,
    oz1.from_sto_move,
    sum(isnull(oz2.qty_orlogo, 0) - isnull(oz2.qty_zarlaga, 0))
        qty_oz,
    oz1.cost_prev
from
    #oz oz1 left join
    #oz oz2 on
        oz1.product_id = oz2.product_id and
        oz1.[date] > oz2.[date]
group by oz1.product_id, oz1.id, oz1.from_sto_move, oz1.cost_prev
print 'Query finished on: ' + CONVERT(nvarchar(30), GETDATE(), 126)

我需要不到 5 秒的时间。 谢谢

【问题讨论】:

什么版本的 SQL 服务器? MSSQL2008 R2 Enterprice 我注意到 id 在示例数据中不是唯一的,这是偶然还是“预期行为”? 【参考方案1】:

我唯一的扩展建议是构建一个覆盖索引,但是引擎准备索引比运行查询花费更多时间吗?

尝试在 (product_id, [date], id, from_sto_move, cost_prev ) 上创建索引。

由于这是一个#temp 表,我认为使索引聚集在一起并不重要,而不仅仅是拥有连接/组的关键元素。日期是连接的关键组成部分。

此外,您正在显示 #oz 的创建临时表,但没有显示您如何填充它。也许将原始原始数据的填充方式提高一个级别也可能会有所帮助,方法是按预先排序的顺序准备临时表,然后自行加入您正在寻找的结果。

【讨论】:

我编辑了我的问题。现在您可以下载包含完整数据的完整查询。请试试这个。【参考方案2】:

您能否在“product_id”列的表中添加一个聚集索引,并在其中包含“id”和“from_sto_move”。如果有帮助,请告诉我。

您能在表格中添加另一个索引吗?

CREATE NONCLUSTERED INDEX [_dta_index_oz_7_148195578__K3_K1_K2_K7_4] ON [dbo].[oz]
(
[product_id] ASC,
[id] ASC,
[from_sto_move] ASC,
[cost_prev] ASC
)
INCLUDE (   [date]) WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]

这是您可以创建的第二个索引:

CREATE NONCLUSTERED INDEX [_dta_index_oz_7_148195578__K3_K4_5_6] ON [dbo].[oz]
(
[product_id] ASC,
[date] ASC
)
INCLUDE (   [qty_orlogo],
[qty_zarlaga]) WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]

让我知道它的效果如何。

【讨论】:

运行时间降至 7 秒。效果很好。 但我怕7秒不够。要求小于 5 秒 我编辑了我的问题。现在您可以下载包含完整数据的完整查询。 我提高了大约 75% :) 你有进步吗?【参考方案3】:

这似乎工作得很好,据我所知,它返回完全相同的结果(CHECKSUM_AGG(BINARY_CHECKSUM(*)) 在两个结果集中返回相同的值)。

;WITH src
  AS (SELECT oz1.product_id,
             oz1.id,
             oz1.from_sto_move,
             qty_oz = ISNULL((SELECT sum(isnull(oz2.qty_orlogo, 0) - isnull(oz2.qty_zarlaga, 0))  
                                FROM  #oz oz2 
                               WHERE oz2.product_id  = oz1.product_id 
                                 AND oz2.[date] < oz1.[date]), 0),
             oz1.cost_prev
        FROM #oz oz1)

SELECT product_id,
       id,
       from_sto_move,
       sum(qty_oz) as qty_oz,
       cost_prev
  FROM src
 GROUP BY product_id,
          id,
          from_sto_move,
          cost_prev

它的“伟大”之处在于它不依赖任何索引;事实上,它甚至直接在堆上也能很好地工作,这样您就不会浪费时间创建索引。

也就是说,即使表上没有真正的 PK(无论是否为临时表);我总是确保在创建表时至少添加一个IDENTIY() 列,并在加载数据之前上放置聚集索引。根据我的经验,它使加载数据的速度稍快一些。

【讨论】:

奇怪但真实,如果#oz 上没有索引,这效果最好。当我在product_idfrom_sto_move 上添加索引时,查询大约需要 4 秒;当我没有索引时,只需不到 2 秒。 SQL 有时会很奇怪 =) 您的查询神奇地运行了 3 秒。我从没想过。感谢您的大力帮助! 很高兴它帮助了你。仅供参考,我也没想到会产生这么大的影响,但幸运的是你提供了可以使用的数据。

以上是关于需要优化 mssql 查询以获得最快的速度的主要内容,如果未能解决你的问题,请参考以下文章

Node MySQL 以最快的速度执行多个查询

优化给定的 sql 查询以提高速度

需要优化查询以在索引视图中使用

sql优化

MSSQL里面建索引的问题

需要帮助优化 mysql 查询以使其按索引快速排序