SQL Server:查询运行速度非常慢(最多20秒)

时间:2015-03-04 12:01:35

标签: sql sql-server database performance

我现在来这里遇到了问题"我的"数据库查询。它在"冷"上执行约22-25秒。数据库,我拼命寻找任何改进它的方法。

我喜欢跳过任何与表格相关的建议,因为我无法改变其结构(太糟糕)。我得到了我已经给予的东西......我只是想找到任何解决方案来改善这个查询的性能。我知道数据库设计不合理,但目前我无法做到这一点,所以如果没有办法改进查询,我会接受。< / p>

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
SET STATISTICS PROFILE ON;

SELECT <STUFF TO SELECT>
FROM [dbo].[2009_Zlecenia] AS Z 
OUTER APPLY (SELECT TOP 1 M1.DataDo AS 'DataRozladunku', M1.Kod, M1.Miasto, MK1.Skrot FROM [dbo].[MiejscaZaladunkuRozladunku] AS M1 LEFT JOIN [dbo].[Kraje] AS MK1 ON M1.Kraj = MK1.Id WHERE M1.Zlecenie = Z.Id AND M1.Rodzaj = 2 ORDER BY Data DESC) AS MZR 
OUTER APPLY (SELECT TOP 1 M2.DataDo AS 'DataZaladunku', M2.Kod, M2.Miasto, MK2.Skrot FROM [dbo].[MiejscaZaladunkuRozladunku] AS M2 LEFT JOIN [dbo].[Kraje] AS MK2 ON M2.Kraj = MK2.Id WHERE M2.Zlecenie = Z.Id AND M2.Rodzaj = 1 ORDER BY Data ASC) AS MZR1 
OUTER APPLY (Select count(FP1.Id) 'Count' FROM [dbo].[2009_FakturyPrzewoznika] AS FP1 WHERE FP1.ZlecenieId = Z.Id group by FP1.ZlecenieId) AS FP 
OUTER APPLY (SELECT count(FP3.ZlecenieId) 'Count' FROM [dbo].[2009_FakturyPrzewoznika] AS FP3 WHERE FP3.ZlecenieId IN (Select Id FROM [dbo].[2009_Zlecenia] WHERE IdZlecenieNadrzedne <> 0 And IdZlecenieNadrzedne = Z.Id) GROUP BY FP3.ZlecenieId) AS FP2 
OUTER APPLY (SELECT TOP 1 Nr FROM [dbo].[2009_KartyDrogowe] AS KD1 LEFT JOIN [dbo].[ZleceniaKartyDrogowej] AS ZKD1 ON ZKD1.KartaDrogowa = KD1.Id WHERE ZKD1.Zlecenie = Z.Id) AS KD 
OUTER APPLY ( Select count(Id) 'Count' FROM [dbo].[2009_Zlecenia] WHERE IdZlecenieNadrzedne <> 0 And IdZlecenieNadrzedne = Z.Id) AS ZP 
LEFT JOIN [dbo].[ZleceniaWalutaObca] AS ZWO ON Z.Id = ZWO.OrderId 
LEFT JOIN [dbo].[Kraje] AS K1 ON Z.TransportZ = K1.Id 
LEFT JOIN [dbo].[Kraje] AS K2 ON Z.TransportDo = K2.Id 
LEFT JOIN [dbo].[Lista] AS L1 ON Z.Status = L1.Id 
LEFT JOIN [dbo].[Uzytkownicy] AS U ON Z.Uzytkownik = U.Id 
LEFT JOIN [dbo].[Oddzialy] AS UO ON U.Oddzial = UO.Id 
LEFT JOIN [dbo].[FakturyZlecen] AS FZ ON FZ.Zlecenie = Z.Id 
LEFT JOIN [dbo].[FakturyZlecen] AS FZ1 ON FZ1.Zlecenie = Z.IdZlecenieNadrzedne 
LEFT JOIN [dbo].[2009_Faktury] AS F1 ON FZ.Faktura = F1.Id 
LEFT JOIN [dbo].[2009_Faktury] AS F2 ON FZ1.Faktura = F2.Id 
LEFT JOIN [dbo].[Firmy] AS FO ON FO.Id = Z.ZleceniodawcaId 
LEFT JOIN [dbo].[Uzytkownicy] AS O1 ON FO.Opiekun1 = O1.Id 
LEFT JOIN [dbo].[Uzytkownicy] AS O2 ON FO.Opiekun2 = O2.Id 
LEFT JOIN [dbo].[Uzytkownicy] AS O3 ON FO.Opiekun3 = O3.Id 
WHERE Z.TypZlecenia = 4 AND Z.Importowane=0 ORDER BY YEAR(Z.DataZlecenia) DESC, Z.Idx DESC, Z.Nr DESC


SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
SET STATISTICS PROFILE OFF;

我会发布执行计划,但它很大。我会敏锐地回答有关它的任何问题! :)

大约80%的查询时间是通过在外部apply子句中进行排序来消耗的。

以下是&#34; hot&#34;执行的统计数据。服务器:

  

(受影响的16467行)

     

表&#39; Uzytkownicy&#39;。扫描计数0,逻辑   读取33042,物理读取0,预读取读取0,lob逻辑读取   0,lob物理读取0,lob预读读取0.

     

表格&#39;坚固&#39;扫描   计数0,逻辑读取50421,物理读取0,预读读取0,   lob逻辑读取0,lob物理读取0,lob预读读取0。

     

表&#39; 2009_Faktury&#39;。扫描计数0,逻辑读取48577,物理   读取0,预读读取0,lob逻辑读取0,lob物理读取   0,lob预读为0.

     

表&#39;工作台&#39;。扫描计数0,逻辑   读取0,物理读取0,预读取读取0,lob逻辑读取0,   lob物理读取0,lob预读读取0.

     

表&#39; FakturyZlecen&#39;。   扫描计数32934,逻辑读取101846,物理读取0,预读   读取0,lob逻辑读取0,lob物理读取0,lob预读   读数为0.

     

表&#39; Oddzialy&#39;。扫描计数1,逻辑读取32935,物理   读取0,预读读取0,lob逻辑读取0,lob物理读取   0,lob预读为0.

     

表&#39; Lista&#39;。扫描计数0,逻辑读取   32934,物理读取0,预读读取0,lob逻辑读取0,lob   物理读取0,lob预读读取0.

     

表&#39; Kraje&#39;。扫描计数2,   逻辑读取65874,物理读取0,预读读取0,lob逻辑   读取0,lob物理读取0,lob预读读取0.

     

表   &#39; ZleceniaWalutaObca&#39 ;.扫描计数1,逻辑读取0,物理读取0,   预读读取0,lob逻辑读取0,lob物理读取0,lob   预读读数为0.

     

&#39;工作表&#39; 。扫描计数65420,逻辑读取    450989 ,物理读取0,预读读取0,lob逻辑读取0,lob   物理读取0,lob预读读取0.

     

表&#39; 2009_Zlecenia&#39;。扫描   计数32635,逻辑读取84027,物理读取0,预读取读取   0,lob逻辑读取0,lob物理读取0,lob预读读取0。

     

表&#39; ZleceniaKartyDrogowej&#39;。扫描计数1,逻辑读取0,物理   读取0,预读读取0,lob逻辑读取0,lob物理读取   0,lob预读为0.

     

表&#39; 2009_FakturyPrzewoznika&#39;。扫描计数   318,逻辑读取687,物理读取0,预读取读取0,lob   逻辑读取0,lob物理读取0,lob预读读取0.

     

表   &#39; MiejscaZaladunkuRozladunku&#39 ;.扫描计数2,逻辑读取5670,   物理读取0,预读读取0,lob逻辑读取0,lob   物理读取0,lob预读读取0。

     

SQL Server执行时间:CPU时间= 1547毫秒,已用时间=   1771 ms。

我突出了&#34;工作台&#34;因为我认为这是表现糟糕的主要原因。

任何有用的建议?

@EDIT

执行计划在这里:

Overview ExecPlan ExecPlan2 ExecPlan3

2 个答案:

答案 0 :(得分:3)

该计划似乎包含大量index spools,这是SQL Server在tempdb中构建临时索引的运算符。至少对于那些情况,永久性指数应该会大大提高绩效。

执行select count(column) SQL Server时计算该列的非空值。使用select count(*)时,将计算行数,SQL Server可以对任何索引执行索引扫描。

最好从计划中检查密钥查找,如果存在实际执行计数很高的查找,则将这些列添加为索引中的包含字段将删除密钥查找。这会增加插入/更新的成本。

将一个大查询分成更小的部分可以帮助优化器选择更好的计划。在具有多个大表的查询中,查询计划创建也可能在超时中结束,从而导致非常糟糕的计划。这可以在查询计划的第一个节点的属性中看到(&#34;优化级别&#34;)

答案 1 :(得分:2)

你肯定要摆脱子选择。每次迭代一行时都会执行它们。您应该尝试离开加入它们并不容易,因为我看到您通过选择前1来限制它们。

糟糕的表现是使用子选择。

我不知道结构以及您可能一眼就能看到的内容,但也许这个简单的提示可以帮助您解决问题。

让我们考虑加载的一行

  • 您从[2009_Zlecenia]
  • 加载行
  • 您加载了子选择MZR的全部
  • 你排序MZR
  • 你冲洗除MZR2的第一行之外的所有行
  • 您加载了子选择MZR2的全部
  • 你排序MZR2
  • 你冲洗除MZR2的第一行之外的所有行
  • 您加载了子选择FP1的所有
  • 你排序FP1
  • 刷新所有行,但第一个是FP1
  • 您加载了子选择FP2的全部
  • 你排序FP2
  • 你刷新除FP2的第一行之外的所有行
  • 您加载了子选择KD的全部
  • 你排序KD
  • 你冲洗所有线路,但第一个是KD
  • 您加载子选择ZP的全部
  • 你排序ZP
  • 你冲洗除了第一个ZP
  • 之外的所有行

你只为所有人做了10次左连接(快速),但考虑子选择为每一行加载的数据。它们是每排新装的。

同时尝试为您过滤的列编制索引http://www.1keydata.com/sql/alter-table-add-index.html 索引将增加内存和硬盘丢失的执行时间。