2011-06-09 73 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可能会扫描该表而不是使用索引,并且稍后必须查找相关列。

相关问题