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 查询缓慢的主要内容,如果未能解决你的问题,请参考以下文章
使用 DbVisualizer 在具有包含 COALESCE() 的唯一索引的表上出现 SQLITE_CORRUPT 错误