2014-10-07 78 views
2

我寫了下面的SQL命令:查詢性能問題與JOIN和RANK()

SELECT *, COALESCE (def.route_step, 'Keine Fehlerinformation') as 'Ausfallort' 
FROM QS_WIP_Errors err 
LEFT JOIN (
    SELECT * FROM 
    (
     SELECT DISTINCT 
       inspect_time, repair_time, serial_number, station, route_step, 
       rank() over (partition by def.serial_number order by inspect_time desc) as [Rang] 
     FROM dbo.View_QS_DEFECTS_Stammdaten def 
     WHERE route_step NOT LIKE 'Analyse' 
    ) AS def WHERE rang=1) as def 
ON err.SERIAL_NUMBER = def.serial_number 
WHERE err.state = 2 
    AND err.ENDTIME >= '2014-10-06 06:00:00.000' 
    AND err.ENDTIME <= '2014-10-07 06:00:00.000' 

我打算做的是:

  • QS_WIP_Errors:讓所有的記錄與state = 2 ;
  • 一段指定的時間;
  • 加入屬性爲serial_number的那些結果與來自視圖dbo.View_QS_Defects_Stammdaten的相應記錄;
  • COALESCE:顯示'Keine Fehlerinformationen萬一'JOIN找不到匹配;
  • from dbo.View_QS_DEFECTS_Stammdaten:得到每個def.serial_number的最新記錄,其中rang=1;
  • 除了最後的route_stepAnalyse

上面的查詢做,它的設計的一切 - 但它不能在期望的時間做到這一點(我放棄它在30分鐘後...)

奇怪的是,當我跳過時間限制(即行AND err.ENDTIME >= '2014-10-06 06:00:00.000' AND err.ENDTIME <= '2014-10-07 06:00:00.000')查詢在幾秒內執行(即根據需要)。

我試過到目前爲止以提高性能:

  • 更換view_QS_DEFECTS_Stammdaten由原始表;
  • 而不是查詢所有列(*)只是選擇一些單柱 - >沒有任何改善

任何人都可以給我一個提示,我怎麼能提高性能???

非常感謝! 我與SQL Server 2012的

回答

3

工作這是您的查詢:

select *, COALESCE(def.route_step, 'Keine Fehlerinformation') as Ausfallort 
from QS_WIP_Errors err left join 
    (select * 
     from (select distinct inspect_time, repair_time, serial_number, station, route_step, 
        rank() over (partition by def.serial_number order by inspect_time desc) as [Rang] 
      from dbo.View_QS_DEFECTS_Stammdaten def 
      where route_step not like 'Analyse' 
      ) as def 
     where rang = 1 
    ) as def 
    on err.SERIAL_NUMBER = def.serial_number 
where err.state = 2 AND 
     err.ENDTIME >= '2014-10-06 06:00:00.000' AND err.ENDTIME <= '2014-10-07 06:00:00.000'; 

一些觀察:

  • 性能可能會受到潛在的視圖來驅動,所以有可能是什麼,可以在這個級別完成。
  • distinct似乎沒有必要。如果你只想要一行,你應該更具體地使用row_number()
  • err上的索引將有所幫助。

所以建立索引QS_WIP_Errors(state, endtime, serial_number)和編寫查詢作爲:

select *, COALESCE(def.route_step, 'Keine Fehlerinformation') as Ausfallort 
from QS_WIP_Errors err left join 
    (select inspect_time, repair_time, serial_number, station, route_step, 
      row_number() over (partition by def.serial_number order by inspect_time desc) as [Rang] 
     from dbo.View_QS_DEFECTS_Stammdaten def 
     where route_step not like 'Analyse' 
    ) as def 
    on err.SERIAL_NUMBER = def.serial_number and rang = 1 
where err.state = 2 AND 
     err.ENDTIME >= '2014-10-06 06:00:00.000' AND err.ENDTIME <= '2014-10-07 06:00:00.000'; 

您也可以嘗試寫這爲outer apply

select *, COALESCE(def.route_step, 'Keine Fehlerinformation') as Ausfallort 
from QS_WIP_Errors err outer apply 
    (select top 1 inspect_time, repair_time, serial_number, station, route_step 
     from dbo.View_QS_DEFECTS_Stammdaten def 
     where route_step not like 'Analyse' and err.SERIAL_NUMBER = def.serial_number 
     order by inspect_time desc 
    ) def 
where err.state = 2 AND 
     err.ENDTIME >= '2014-10-06 06:00:00.000' AND err.ENDTIME <= '2014-10-07 06:00:00.000'; 

有時apply方法優化更好。

1

謝謝@Gordon的回覆。 首先,針對您使用「獨特」和「行號」的提示 - 您確實是對的,我上面的查詢沒有給我想要的結果。 我修改它,然後這樣說:

Select * from (
    select distinct err.SERIAL_NUMBER as 'Err_SERIAL_NUMBER', 
    err.ROUTE_STEP as 'Err_ROUTE_STEP', err.ENDTIME, 
    rank() over (partition by err.serial_Number order by err.endtime asc) as [Rank_err], 
    def.*, COALESCE (def.route_step, 'Keine Fehlerinformation') as 'Ausfallort' 
    from QS_WIP_Errors err LEFT JOIN (
    select * from 
    (
    select distinct inspect_time as 'DefectsInspectTime', serial_number, station, route_step, 
    rank() over (partition by def.serial_number order by def.inspect_time desc) as [Rank_Def] 
    from dbo.View_QS_DEFECTS_Stammdaten def where route_step not like 'Analyse' 
) as def where Rank_Def=1) as def 
    on err.SERIAL_NUMBER = def.serial_number 
    where err.state = 2) as tblJoin 
where tblJoin.Rank_err = 1 
AND tblJoin.ENDTIME >= '2014-10-07 06:00:00.000' AND tblJoin.ENDTIME <= '2014-10-08 06:00:00.000' 

現在我真的得到我想要的值。並且作爲一個不錯的副作用,現在查詢在幾秒鐘內執行。我無法真正解釋它,但它解決了這個問題。這就是爲什麼我把它標爲答案