2011-06-09 88 views
2

在我查詢的其中一個表中,聚簇索引是通過不是主鍵的鍵創建的。 (我不知道爲什麼。)爲什麼SQL Server會選擇「非羣集索引掃描」?

但是,此表的主鍵存在非聚集索引。

在執行計劃中,SQL選擇聚簇索引,而不是我在查詢中使用的主鍵的非聚簇索引。

SQL是否會這樣做?我如何強制SQL選擇非聚集索引呢?


追加更多詳細信息:

表有許多領域和查詢包含許多聯接。讓我抽象一下。

表定義是這樣的:

SlowTable 
[SlowTable_id] [int] IDENTITY(200000000,1) NOT NULL, 
[fk1Field] [int] NULL, 
[fk2Field] [int] NULL, 
[other1Field] [varchar] NULL, 
etc. etc... 

,然後該表的指標是:

fk1Field (Clustered) 
SlowTable_id (Non-Unique, Non-Clustered) 
fk2Field (Non-Unique, Non-Clustered) 
... and 14 other Non-Unique, Non-Clustered indices on other fields 

想必有很多反對fk1Field這就是爲什麼他們選擇這個作爲更加查詢聚集指數的基礎。

查詢我使用一個觀點:

SELECT 
    [field list] 
FROM 
    SourceTable1 S1 
    INNER JOIN SourceTable2 S2 
     ON S2.S2_id = S1.S2_id 
    INNER JOIN SourceTable3 S3 
     ON S3.S3_id = S2.S3_id 
    INNER JOIN SlowTable ST 
     ON ST.SlowTable_id = S1.SlowTable_id 
    INNER JOIN [many other tables, around 7 more...] 

執行計劃是相當大的,與有關的節點說

Hash Match 
(Inner Join) 
Cost: 9% 

用粗箭頭指向

Clustered Index Scan (Clustered) 
SlowTable.fk1Field 
Cost: 77% 

我希望這能夠提供足夠的細節。

謝謝!


附錄2: 更正以前我的帖子。該視圖沒有where子句。這只是一系列內部連接。執行計劃是從一個Insert語句中獲取的,該語句在複雜查詢中使用View(列爲SLOW_VIEW),如下所示:

(此存儲過程所做的是執行一些比例拆分記錄的基礎上,權重,計算針對總百分比這模仿,比如說,從一個帳戶分配一個值,其他帳戶)

INSERT INTO dbo.WDTD(
    FieldA, 
    FieldB, 
    GWB_id, 
    C_id, 
    FieldC, 
    PG_id, 
    FieldD, 
    FieldE, 
    O_id, 
    FieldF, 
    FieldG, 
    FieldH, 
    FieldI, 
    GWBIH_id, 
    T_id, 
    JO_id, 
    PC_id, 
    PP_id, 
    FieldJ, 
    FieldK, 
    FieldL, 
    FieldM, 
    FieldN, 
    FieldO, 
    FieldP, 
    FieldQ, 
    FieldS) 
SELECT DISTINCT 
    @FieldA FieldA, 
    GETDATE() FieldB, 
    @Parameter1 GWB_id, 
    GWBIH.C_id C_id, 
    P.FieldT FieldC, 
    P.PG_id PG_id, 
    PAM.FieldD FieldD, 
    PP.FieldU FieldE, 
    GWBIH.O_id O_id, 
    CO.FieldF FieldF, 
    CO.FieldG FieldG, 
    PSAM.FieldH FieldH, 
    PSAM.FieldI FieldI, 
    SOURCE.GWBIH_id GWBIH_id, 
    ' ' T_id, 
    GWBIH.JO_id JO_id, 
    SOURCE.PC_id PC_id, 
    GWB.PP_id, 
    SOURCE.FieldJ FieldJ, 
    1 FieldK, 
    ROUND((SUM(GWBIH.Total)/AGG.Total) * SOURCE.Total, 2) FieldL, 
    ROUND((SUM(GWBIH.Total)/AGG.Total) * SOURCE.Total, 2) FieldM, 
    0 FieldN, 
    ' ' FieldO, 
    ESGM.FieldP_flag FieldP, 
    SOURCE.FieldQ FieldQ, 
    '[UNPROCESSED]' 
FROM 
    dbo.Table1 GWBIH 
    INNER JOIN dbo.Table2 GWBPH 
     ON GWBPH.GWBP_id = GWBIH.GWBP_id 
    INNER JOIN dbo.Table3 GWB 
     ON GWB.GWB_id = GWBPH.GWB_id 
    INNER JOIN dbo.Table4 P 
     ON P.P_id = GWBPH.P_id 
    INNER JOIN dbo.Table5 ESGM 
     ON ESGM.ET_id = P.ET_id 
    INNER JOIN dbo.Table6 PAM 
     ON PAM.PG_id = P.PG_id 
    INNER JOIN dbo.Table7 O 
     ON O.dboffcode = GWBIH.O_id 
    INNER JOIN dbo.Table8 CO 
     ON 
      CO.Country_id = O.Country_id 
      AND CO.Brand_id = O.Brand_id 
    INNER JOIN dbo.Table9 PSAM 
     ON PSAM.Office_id = GWBIH.O_id 
    INNER JOIN dbo.Table10 PCM 
     ON PCM.PC_id = GWBIH.PC_id 
    INNER JOIN dbo.Table11 PC 
     ON PC.PC_id = GWBIH.PC_id 
    INNER JOIN dbo.Table12 PP 
     ON PP.PP_id = GWB.PP_id 
      -- THIS IS THE VIEW THAT CONTAINS THE CLUSTERED INDEX SCAN 
    INNER JOIN dbo.SLOW_VIEW GL 
     ON GL.JO_id = GWBIH.JO_id 
    INNER JOIN (
     SELECT 
      GWBIH.C_id C_id, 
      GWBPH.GWB_id, 
      SUM(GWBIH.Total) Total 
     FROM 
      dbo.Table1 GWBIH 
      INNER JOIN dbo.Table2 GWBPH 
       ON GWBPH.GWBP_id = GWBIH.GWBP_id 
      INNER JOIN dbo.Table10 PCM 
       ON PCM.PC_id = GWBIH.PC_id 
     WHERE 
      PCM.Split_flag = 0 
      AND GWBIH.JO_id IS NOT NULL 
     GROUP BY 
      GWBIH.C_id, 
      GWBPH.GWB_id 
      ) AGG 
     ON AGG.C_id = GWBIH.C_id 
      AND AGG.GWB_id = GWBPH.GWB_id 
    INNER JOIN (
     SELECT 
      GWBIH.GWBIH_id GWBIH_id, 
      GWBIH.C_id C_id, 
      GWBIH.FieldQ FieldQ, 
      GWBP.GWB_id GWB_id, 
      PCM.PC_id PC_id, 
      CASE 
      WHEN WT.FieldS IS NOT NULL 
       THEN WT.FieldS 
      WHEN WT.FieldS IS NULL 
       THEN PCMS.FieldT 
      END FieldJ, 
      SUM(GWBIH.Total) Total 
     FROM 
      dbo.Table1 GWBIH 
      INNER JOIN dbo.Table2 GWBP 
       ON GWBP.GWBP_id = GWBIH.GWBP_id 
      INNER JOIN dbo.Table4 P 
       ON P.P_id = GWBP.P_id 
      INNER JOIN dbo.Table10 PCM 
       ON PCM.PC_id = GWBIH.PC_id 
      INNER JOIN dbo.Table11 PCMS 
       ON PCMS.PC_id = PCM.PC_id 
      LEFT JOIN dbo.WT WT 
       ON WT.ET_id = P.ET_id 
       AND WT.PC_id = GWBIH.PC_id 
     WHERE 
      PCM.Split_flag = 1 
     GROUP BY 
      GWBIH.GWBI_id, 
      GWBIH.C_id, 
      GWBIH.FieldQ, 
      GWBP.GWB_id, 
      WT.FieldS, 
      PCM.PC_id, 
      PCMS.ImportCode 
      ) SOURCE 
     ON SOURCE.C_id = GWBIH.C_id 
      AND SOURCE.GWB_id = GWBPH.GWB_id 
WHERE 
    PCM.Split_flag = 0 
    AND AGG.Total > 0 
    AND GWBPH.GWB_id = @Parameter1 
    AND NOT EXISTS (
     SELECT * 
     FROM dbo.WDTD 
     WHERE 
      TD.C_id = GWBIH.C_id 
      AND TD.FieldA = GWBPH.GWB_id 
      AND TD.JO_id = GWBIH.JO_id 
      AND TD.PC_id = SOURCE.PC_id 
      AND TD.GWBIH_id = ' ') 
GROUP BY 
    GWBIH.C_id, 
    P.FieldT, 
    GWBIH.JO_id, 
    GWBIH.O_id, 
    GWBPH.GWB_id, 
    P.PG_id, 
    PAM.FieldD, 
    PP.FieldU, 
    GWBIH.O_id, 
    CO.FieldF, 
    CO.FieldG, 
    PSAM.FieldH, 
    PSAM.FieldI, 
    GWBIH.JO_id, 
    SOURCE.PC_id, 
    GWB.PP_id, 
    SOURCE.FieldJ, 
    ESGM.FieldP_flag, 
    SOURCE.GWBIH_id, 
    SOURCE.FieldQ, 
    AGG.Total, 
    SOURCE.Total 

附錄3:在做的一個執行計劃選擇聲明的觀點,我看到這個:

Hash Match  <==== Bitmap   <------ etc... 
(Inner Join)   (Bitmap Create) 
Cost: 0%    Cost: 0% 
    ^
    | 
    | 
Parallelism       Clustered Index Scan (Clustered) 
(Repartition Streams) <====  Slow_Table.fk1Field 
Cost: 1%        Cost: 98% 

附錄4:我想我發現了這個問題。聚集索引掃描不是指引用主鍵的my子句,而是另一個需要一個字段的子句,它在某種程度上與上面的fk1Field相關。

+1

需要更多信息:表+索引+計劃 – gbn 2011-06-09 07:47:24

+0

有很多可能性,其範圍不可能在沒有進一步信息的情況下精確縮小,如相關的模式信息,實際執行計劃,查詢文本等。 – 2011-06-09 07:48:20

+0

info *不夠*你的WHERE和GROUP BY子句是什麼?另外,每個索引都是單列索引嗎? – gbn 2011-06-09 10:03:26

回答

4

的最有可能的一個:

  • 太多行做出有效的索引
  • 指標不符合ON/WHERE條件
  • 指數不覆蓋和SQL Server避免了關鍵查找

編輯,後更新:

你的索引是無用的,因爲他們都是單列索引,因此它執行聚簇索引掃描。

您需要一個與您的SELECT列表中的ON,WHERE,GROUP BY條件和INCLUDES匹配的索引。

1

如果您正在執行的查詢未選擇記錄的一小部分,SQL Server可能會選擇忽略任何「非常有用」的非聚集索引,並只掃描聚集索引(在此實例中,很可能是表中的所有行) - 邏輯是執行查詢所需的I/O數量與全面掃描所需的非聚集索引超出的數量。

如果您可以發佈表格模式+示例查詢,我相信我們可以提供更多信息。

1

理想情況下,您不應該告訴SQL Server執行任何操作,如果您給它一個很好的查詢,它可以選擇最好的。查詢提示是爲了引導引擎而創建的,但您不應該只使用它。

有時,對錶進行聚簇的方式不同,主鍵很少見,但它很有用(聚類控制數據佈局,而主鍵確保正確性)。

我可以準確地告訴你爲什麼SQL Server選擇聚集索引,如果你告訴我你的查詢和模式,否則我只會猜測可能的原因和執行計劃在這些情況下是有幫助的。

對於非聚集索引的考慮,它必須對查詢有意義,並且如果您的非聚集索引不包含您的查詢,則根本沒有保證它將被使用。

1

聚簇索引掃描本質上是一個表掃描(在恰好有聚簇索引的表上)。你真的應該發表你的陳述來得到更好的答案。您的where子句可能無法搜索(請參閱sargs),或者如果您選擇多條記錄,則sql server可能會掃描該表而不是使用索引,並且稍後必須查找相關列。

相關問題