簡體   English   中英

需要進一步優化此 SQL Server 查詢的建議

[英]Need suggestions to further optimize this SQL Server query

我寫了這個非常簡單的查詢,它現在已經運行了 16 多個小時。 我已經嘗試了所有方法來優化它,但不知道如何進一步改進它。 請幫忙。

select 
    a.*, b.TM_IN_XIT 
into
    scratch.dbo.ab_peak2 
from 
    scratch.dbo.ab_peak1 a 
left join 
    Scratch.dbo.ab_tnt b on a.DC_ZIP between b.ORIG_ZIP_low 
                         and b.ORIG_ZIP_high 
                         and a.Destination between b.DEST_ZIP_low and b.DEST_ZIP_high  
                         and a.Carr_Mode = b.Mode;

scratch.dbo.ab_peak1如下所示,有大約 700k 條記錄:

+-----------------------------------------------+
| ShipmentNumber  DC_ZIP  Destination Carr_Mode |
+-----------------------------------------------+
| 252838748       60622       10016      A      |
| 252731857       60622       40517      A      |
| 252685087       60622       91601      B      |
| 252574905       60622       7017       B      |
| 252877256       60622       97230      A      |
| 254791362       20166       54971      B      |
| 255866277       60622       19131      A      |
| 255728088       60622       27713      B      |
| 255614555       60622       10009      A      |
| 255823071       60622       33556      B      |
+-----------------------------------------------+

Scratch.dbo.ab_tnt如下所示,有大約 150 萬條記錄:

+-----------------------------------------------------------------------------------+
| Mode    ORIG_ZIP_low    ORIG_ZIP_high   DEST_ZIP_low    DEST_ZIP_high   TM_IN_XIT |
+-----------------------------------------------------------------------------------+
|   A        41042            41042          62556            62556          2      |
|   B        41042            41042          62556            62556          3      |
|   A        41042            41042          62557            62557          1      |
|   B        41042            41042          62557            62557          2      |
|   A        41042            41042          62558            62563          2      |
|   B        41042            41042          62558            62563          3      |
|   A        41042            41042          62565            62567          1      |
|   B        41042            41042          62565            62567          2      |
|   A        41042            41042          62568            62570          2      |
|   B        41042            41042          62568            62570          3      |
+-----------------------------------------------------------------------------------+

我想要實現的目標 - “a”是一個 Shipments 表,而“b”是一個表,其中包含所有出發地-目的地組合的運輸時間。 “b”表的結構基於 zip 范圍,如上所示。 我試圖通過在“b”表中查找來為“a”表的每批貨物引入運輸時間。

我已經嘗試過以下操作:

  1. TNT 表中保留的郵政編碼 >= min(PEAK1 表中的郵政編碼)和 <= max(PEAK1 表中的郵政編碼)
  2. 在 TNT 表的所有列上創建索引。

還有其他建議嗎?

對於此查詢:

select a.*, b.TM_IN_XIT 
into scratch.dbo.ab_peak2 
from scratch.dbo.ab_peak1 a left join
     Scratch.dbo.ab_tnt b
     on a.DC_ZIP between b.ORIG_ZIP_low and b.ORIG_ZIP_high and
        a.Destination between b.DEST_ZIP_low and b.DEST_ZIP_high and
        a.Carr_Mode = b.Mode;

您首先想嘗試索引。 顯而易見的嘗試是ab_tnt(mode, orig_zip_low, orig_zip_high, dest_zip_low, dest_zip_high, tm_in_xit)

我也可能傾向於這樣寫查詢:

select a.*,
       (case when a.DC_ZIP <= b.ORIG_ZIP_high and a.destination <= b.DESC_ZIP_high
             then b.TM_IN_XIT
        end) as TM_IN_XIT
into scratch.dbo.ab_peak2 
from scratch.dbo.ab_peak1 a outer apply
     (select top 1 b.*
      from Scratch.dbo.ab_tnt b
      where a.DC_ZIP >= b.ORIG_ZIP_low and
            a.Destination >= b.DEST_ZIP_low and
            a.Carr_Mode = b.Mode
      order by b.ORIG_ZIP_low, b.DEST_ZIP_low
     ) b;

現在,這不是完全相同的查詢。 它返回第一個可能匹配的郵政編碼。 這個想法是子查詢可能會適當地使用ab_tnt(mode, b.ORIG_ZIP_low, b.DEST_ZIP_low)上的索引。

然后case語句確定是否真的匹配。

我在一個維度上非常成功地使用了這個邏輯(例如處理 IP 范圍)。 我沒有將它用於二維,但是如果您當前的查詢已經運行了一天的大部分時間,那么值得嘗試。

注意:您可以使用(select top 1000 * from scratch.dbo.ab_peak1) a而不是表,通過在記錄子集上運行來測試性能。

只是一個想法,但您是否嘗試過枚舉ab_tnt所有可能組合,並使用結果加入ab_peak1 這是一個使用公共表表達式的示例,但臨時表可能會更好。 此外,此答案假定您有一個Integers表。

;with dest as (
    select dest_zip = i.I, tnt.Mode, orig_zip_low, orig_zip_high, tm_in_xit
    from Integers i
         join ab_tnt tnt on i.I between tnt.dest_zip_low and tnt.dest_zip_high
)
, tnt as (
    select dest.Mode, dest_zip, orig_zip = i.I, dest.tm_in_xit
    from Integers i
         join dest on i.I between dest.orig_zip_low and dest.orig_zip_high

)
select * 
from ab_peak1
    join tnt 
         on ab_peak1.DC_ZIP = tnt.orig_zip
        and ab_peak1.Destination = tnt.dest_zip
        and ab_peak1.Carr_Mode = tnt.Mode

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM