我们有一个问题,我们的表上的索引被忽略,sql Server 2000正在执行表扫描.我们可以使用WITH(INDEX =< index_name>)子句来强制使用索引,但是不希望这样做.
作为开发人员,我在编写T-sql时非常熟悉sql Server,但是分析和性能调优不是我的强项.我正在寻找任何关于为什么会发生的建议和指导.
更新:
我应该说我们已经重建了所有索引和更新的索引统计信息.
其中一个罪魁祸首的表定义如下:
CREATE TABLE [tblinvoices] ( [CustomerID] [int] NOT NULL,[InvoiceNo] [int] NOT NULL,[InvoiceDate] [smalldatetime] NOT NULL,[InvoiceTotal] [numeric](18,2) NOT NULL,[AmountPaid] [numeric](18,2) NULL CONSTRAINT [DF_tblinvoices_AmountPaid] DEFAULT (0),[DateEntered] [smalldatetime] NULL CONSTRAINT [DF_tblinvoices_DateEntered] DEFAULT (getdate()),[PaymentRef] [varchar](110),[PaymentType] [varchar](10),[SyncStatus] [int] NULL,[PeriodStart] [smalldatetime] NULL,[DateIssued] [smalldatetime] NULL CONSTRAINT [DF_tblinvoices_dateissued] DEFAULT (getdate()),CONSTRAINT [PK_tblinvoices] PRIMARY KEY NONCLUSTERED ( [InvoiceNo] ASC ) ON [PRIMARY] ) ON [PRIMARY]
此表上还有一个其他索引(我们希望使用sql):
CustomerID (Non-Unique,Non-Clustered)
以下查询执行表扫描,而不是使用CustomerID索引:
SELECT CustomerID,Sum(InvoiceTotal) AS SumOfInvoiceTotal,Sum(AmountPaid) AS SumOfAmountPaid FROM tblInvoices WHERE CustomerID = 2112 GROUP BY customerID
更新:
在回答Autocracy’s question时,这两个查询都执行表扫描.
更新:
在回答Quassnoi’s question关于DBCC SHOW_STATISTICS的数据是:
RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS 1667 246 454 8 27.33333 2112 911 3427 16 56.9375 2133 914 775 16 57.125
解决方法
最好的做法是通过在CustomerID索引中包含InvoiceTotal和AmountPaid列来使索引成为覆盖索引. (在sql 2005中,您可以将它们添加为“included”列)在sql 2000中,必须将它们添加为其他键列.)如果这样做,我将保证查询优化器将选择您的索引*.
说明:
索引似乎总是有用的,但是使用(不覆盖)索引存在隐藏的成本,也就是“书签查找”,必须完成以检索主要可能需要的任何其他列表.这种书签查找是一项昂贵的操作,并且(一个可能的)原因是查询优化器可能不会选择使用索引.
通过在索引本身中包含所有必需的列,这个书签查找是完全避免的,优化器不必玩这个小游戏,如果使用索引是“值得的”.
(*)或者我将退还您的StackOverflow积分.只要发送一封自封,加盖信封给…
编辑:是的,如果您的主键不是聚集索引,那么一定要做到这一点!但即使是这样的变化,使您的CustomerID索引成为覆盖指数,应该将性能提高一个数量级(10倍或更高)!