NewRelic 在具有适当索引的表之一上报告的 SQL Server 2008 查询缓慢

Posted

技术标签:

【中文标题】NewRelic 在具有适当索引的表之一上报告的 SQL Server 2008 查询缓慢【英文标题】:SQL server 2008 query slowness reported by NewRelic on one of table which is having proper indexes 【发布时间】:2014-02-20 09:07:09 【问题描述】:

我们正在使用带有 nHibernate 的 ASP.NET MVC 从 SQL Server 2008 获取数据。最近我们开始使用 New Relic 并注意到其中一个表(在暂存中大约有 6+ 百万行,在生产中有 10+ 百万行)正在占用更多时间通过简单查询(无需任何连接)返回数据

我们已经验证了必填字段上存在索引,并且数据库维护作业运行正常。

这是表结构

CREATE TABLE [dbo].[OfferTable](
[OfferID] [int] IDENTITY(1,1) NOT NULL,
[Offer] [nvarchar](50) NOT NULL,
[IssueDate] [datetime] NOT NULL,
[ExpiryDate] [datetime] NOT NULL,
[UserId] [nvarchar](255) NULL
PRIMARY KEY CLUSTERED 
(
[OfferID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,   ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]

IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo]. [OfferTable]') AND name = N'IX_OfferTable_Offer')
CREATE UNIQUE NONCLUSTERED INDEX [IX_OfferTable_Offer] ON [dbo].[OfferTable] 
(
    [Offer] ASC
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

nHibernate 正在生成以下查询以从数据库中获取行(从 sql profiler 获取)

exec sp_executesql N'select offertable0_.OfferId as OfferId22_, offertable0_.Offer as Offer_22, offertable0_.IssueDate as IssueDate22_, offertable0_.ExpiryDate as ExpiryDate22_,offertable0_.UserId as UserId22_ from OfferTable  offertable0_  where (offertable0_.Offer is null) and (@p0 is null) or offertable0_.Offer=@p0',N'@p0 nvarchar(4000)',@p0=N'Someoffer'

查询执行计划显示为 Offer 字段的 Index Seek,然后 Key Lookup on OfferID(聚集索引),然后是嵌套循环

SET STATISTICS IO ON 命令给出以下输出

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'OfferTable'. Scan count 0, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

根据 NewRelic,上面的查询非常不稳定,需要 600 毫秒到 29,300 毫秒之间的任何时间,这是不可接受的。直接从 SQL Management Studio 执行相同的查询完全不需要时间。

即使是 NewRelic 也报告此查询的速度慢了 26,800 毫秒。

SELECT offertable_.OfferId AS col_0_0_ FROM OfferTable offertable_ WHERE offertable_.OfferId=@p0

我们能够为暂存环境获取 DBCC SHOW_STATISTICS,因为我们无法直接访问数据库。

Name                              Updated              Rows      Rows Sampled  Steps  Density  Average key length String Index Filter Expression    Unfiltered Rows
--------------------------------- -------------------- --------- ------------- ------ -------- ------------------ ------------ -------------------- --------------------
PK__OfferTab__8EBCF0B1762C88DA    Feb 17 2014 11:47PM  6471738   87058         196    1        4                  NO           NULL                 6471738


All density   Average Length Columns
------------- -------------- ---------------
2.51234E-07   4              OfferId

RANGE_HI_KEY RANGE_ROWS    EQ_ROWS       DISTINCT_RANGE_ROWS  AVG_RANGE_ROWS
------------ ------------- ------------- -------------------- --------------
2077         0             1             0                    1
254978       33824.68      1             33823                1.000041
255503       38071.39      1             524                  72.65533
425848       18998.45      1             18998                1
572688       38071.39      1             38061                1.000283
573083       28534.92      1             394                  72.42365
808660       38071.39      1             38061                1.000283
865309       38071.39      1             38061                1.000283
1466077      38071.39      1             38061                1.000283
1466464      28534.92      1             386                  73.92466
1491230      38071.39      1             24765                1.537306
1703369      18998.45      1             18998                1

  ......


72632182     38071.39      1             38061                1.000283
72632801     38071.39      1             618                  61.6042
72633595     38071.39      1             793                  48.00932
72635990     38071.39      1             2394                 15.90284
72647229     38071.39      1             11238                3.387738
72647764     33973.69      1             534                  63.62114
72647766     0.9999998     1             1                    1


Name                 Updated              Rows     Rows Sampled  Steps  Density       Average key length String Index Filter Expression  Unfiltered Rows
-------------------- -------------------- -------- ------------- ------ ------------- ------------------ ------------ ------------------ --------------------
IX_OfferTable_Offer  Feb 17 2014 12:12AM  6694454  94967         195    1             60                 YES          NULL               6694454

All density   Average Length Columns
------------- -------------- ----------------
1.493774E-07  56             Offer
1.493774E-07  60             Offer, OfferId

RANGE_HI_KEY                                       RANGE_ROWS    EQ_ROWS       DISTINCT_RANGE_ROWS  AVG_RANGE_ROWS
-------------------------------------------------- ------------- ------------- -------------------- --------------
//+7ubDjuOYu54oCOmn9yqoSaGY=                       0             1             0                    1
/EiSLpejJg0iL3CIWpUwpHrKuN0=                       32068.48      1             32068                1
/Vdj7sd2XQYqH1fULVIjcvEKpNk=                       54177.36      1             54138                1.000732
+ATAAsm2GiZT8p6nq5PcoKP6WwM=                       36094.7       1             36091                1.000089
+ijb5mACGIixMdHwZ7bbN8d3wPE=                       27053.36      1             27053                1
+tIz35UIZ+5lMJAVJIloZ/UNBks=                       36094.7       1             36091                1.000089
06PLbtzHQ5d0011ruV3JKngyHX4=                       36094.7       1             36091                1.000089
0j9ZQAfUIfmuGmWnhvY2dDzyjgo=                       36094.7       1             36091                1.000089
0rDVT9rzqhHioz7DEFWs1surUr0=                       27053.36      1             27053                1
11ybw3Kws7ral/jxwmGvhcPqLSA=                       36094.7       1             36091                1.000089
1KEbJtyPiSI4+uyqipqU8TzFvLM=                       45136.03      1             45115                1.000474
1VnZxvlS1zb7TvQYHaF1NLz+X/Y=                       36094.7       1             36091                1.000089
26qVdhVKpWdPnkc0F1cpPhCxZE8=                       27053.36      1             27053                1
2joJSKCwIdoOHuiXu3nh+TeugGU=                       36094.7       1             36091                1.000089

 .....

YCRN93l3z9kZq9O8XmhTkfAc4t0=                       45136.03      1             45115                1.000474
YJpsDBYjGsM8E00Qso5jA2pEDvQ=                       45136.03      1             45115                1.000474
YqYLAWj3RAy1Eds1U5AJ3v6LyDI=                       45136.03      1             45115                1.000474
yxwmZJ4u++qKMFUZ3BLuRUVEECo=                       45136.03      1             45115                1.000474
Z6qEakF5+YM1ufMQud2tnSWbPXs=                       45136.03      1             45115                1.000474
ZF9irQvOCQRkt2s4Af7AftxHF2w=                       45136.03      1             45115                1.000474
ZLWmCLRC4tfKQ721jJRXB2WrE2s=                       45136.03      1             45115                1.000474
zsl5/65fRzNsVrHwRmB3Ta29e94=                       45136.03      1             45115                1.000474
ZZZHu1NznjtILSTYu/6jp5CK0mY=                       48455.89      1             48428                1.00058

我们还使用了数据库引擎优化顾问,它推荐了包含(覆盖索引)的新索引

请谁能帮我理解为什么 NewRelic 报告查询缓慢?与nHibernate有关吗?应该使用覆盖索引,为什么?

提前致谢:)

【问题讨论】:

【参考方案1】:

标准应该是(@p0 is null or offertable0_.Offer=@p0') 而不是(@p0 is null) or offertable0_.Offer=@p0'?当参数为空时,修复该问题应该会显着提高性能。查询缓慢的一个常见原因是该列是 varchar,但 NHibernate 提供了一个 nvarchar 参数,但这里似乎不是这种情况。

如果您经常在优惠上选择使用标准,那么索引可能会有很大帮助。但是由于主键SELECT offertable_.OfferId AS col_0_0_ FROM OfferTable offertable_ WHERE offertable_.OfferId=@p0 的查询出现了同样的问题,所以我怀疑你的根本原因不同。

【讨论】:

谢谢杰米。是的,这看起来像是其他问题,我们已经让 DBA 来检查发生了什么。

以上是关于NewRelic 在具有适当索引的表之一上报告的 SQL Server 2008 查询缓慢的主要内容,如果未能解决你的问题,请参考以下文章

在Oracle中合理创建数据库的索引

在具有聚集列存储索引的表上创建触发器 - 错误

从大表中分块提取报告

mysql在具有1亿行的表上创建索引

如何正确索引在具有多个连接的查询中使用的表

使用 DbVisualizer 在具有包含 COALESCE() 的唯一索引的表上出现 SQLITE_CORRUPT 错误