需要优化 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_id
和from_sto_move
上添加索引时,查询大约需要 4 秒;当我没有索引时,只需不到 2 秒。 SQL 有时会很奇怪 =)
您的查询神奇地运行了 3 秒。我从没想过。感谢您的大力帮助!
很高兴它帮助了你。仅供参考,我也没想到会产生这么大的影响,但幸运的是你提供了可以使用的数据。以上是关于需要优化 mssql 查询以获得最快的速度的主要内容,如果未能解决你的问题,请参考以下文章