(Azure支持提供了模糊的答案,因此我希望转向Stack Overflow!:))
用户抱怨查询超时错误。我从MSMS运行两次相同查询(相同参数)。第一次运行需要 looong (23s或有时50s),第二次,第三次等运行需要< 1s。执行计划是相同的,子树成本为0.0671 ..
我注意到的差异是第一个执行计划中的WaitStats
部分,其中包含以下值:
WaitCount: 2751
WaitTimeMS: 6
WaitType: MEMORY_ALLOCATION_EXT
WaitCount: 2751
WaitTimeMS: 6
WaitType: IO_QUEUE_LIMIT
WaitCount: 669
WaitTimeMS: 20360
WaitType: PAGEIOLATCH_SH
Azure SQL DTU最多平均值为5%
Azure支持称它可能是执行计划的编译时间。我怀疑,因为clearing the Proc Cache 没有在第一次运行后重新引入长时间等待。
执行计划"叶子"是Index Seek (NonClustedred)
,Key Lookup (Clustered)
和RID Lookup (Heap)
。 RID Lookup
为39%(0.0671)。返回一行(即 TOP 1
)。
使用CROSS APPLY
的查询中有3个表。最大的一行有800万行,包含一个~40KB VARBINARY
列(未在查询中的任何地方引用或返回)。
DECLARE @p0 VARCHAR(50); SET @p0 = '<GUID1>'
SELECT TOP 1 p.Id, p.DateCreatedUtc, p.PreviousOwnerId
FROM (
-- last project save
SELECT ps.Id AS psId, p.*
FROM Projects p
CROSS APPLY (
SELECT TOP 1 *
FROM ProjectSaves
WHERE ProjectId = p.Id
ORDER BY LastModifiedUtc DESC
) AS ps
WHERE p.OwnerId = @p0
) p
CROSS APPLY (
SELECT TOP 1 *
FROM ProjectSavePhotos
WHERE ProjectSaveId = p.psId AND (name LIKE 'uploads%')
) ps
WHERE P.IsDeleted = 0 AND p.Id NOT IN ('<GUID2>')
ORDER BY p.DateCreatedUtc DESC
p.OwnerId
已建立索引,Azure会自动创建另外两个索引:
OwnerId
和Id
以及IsDeleted
,OwnerId
和Id
ps.ProjectId
已编入索引并包含LastModifiedUtc
psp.ProjectSaveId
已编入索引并包含name
如何诊断20世纪PAGEIOLATCH_SH
的根本原因?可能只是VARBINARY
列的存在吗?如果是这样,我该如何确认?
https://www.sqlshack.com/handling-excessive-sql-server-pageiolatch_sh-wait-types/
https://sqlperformance.com/2014/06/io-subsystem/knee-jerk-waits-pageiolatch-sh
答案 0 :(得分:2)
任何类型的数据都存储为SQL Server中的页面。根据页面包含的内容(数据,索引等),有不同类型的页面。请参阅documentation page。
SQL Server中数据存储的基本单位是页面。分配给数据库中的数据文件(.mdf或.ndf)的磁盘空间在逻辑上被划分为从0到n连续编号的页面。磁盘I / O操作在页面级别执行。也就是说,SQL Server读取或写入整个数据页。
当您对数据库运行查询时,SQL引擎将查看系统内存(缓冲区)以查看它是否具有执行查询所需的所有页面。如果缺少某些页面,SQL引擎会将它们从磁盘加载到内存中。
PAGEIOLATCH_SH
等待对应于从磁盘拉到内存(缓冲区)的页面。一旦页面被加载到系统内存中,它们就会一直存在,直到被驱逐。这就是为什么第一次运行查询比后续运行花费更多时间的原因。在第一次运行期间,SQL Engine需要从磁盘检索数据。对于后续运行,情况不再如此。
要减少第一个查询等待,有不同的策略。正如Alberto所提到的,如果经常运行此查询,则页面不太可能从缓冲区中逐出。如流水所述,您可以重写查询或创建新索引,以便SQL引擎不必加载这么多页面。请发布查询计划以供进一步调查。
答案 1 :(得分:1)
除非我遗漏了某些内容,否则这听起来很正常,但我必须看到执行计划。你可能想摆脱那个Key Lookup。 Key Lookup是否抓住了Index Seek中使用的索引中缺少的列?如果是,请将其添加到Index Seek中的索引,看看会发生什么。使用如此大的表的交叉应用会占用大量的缓冲区空间,具体取决于它的宽度,但是如果没有查看查询,我就无法确定是否有更好的方法来获取数据。 这也可能有所帮助: https://stackoverflow.com/a/17572392/163072
向ProjectSaves添加群集PK也可能会产生很大的不同。
答案 2 :(得分:1)
您看到的是SQL Azure数据库在数据库未使用一段时间或数据库层已缩放后收缩内存分配的影响。行为正如您所提到的,第一次执行或前几次执行的性能都很差,直到内存分配恢复正常。您不会在连续使用的数据库中看到它。
内存分配上的这种行为会在第一次执行查询时创建您遇到的等待,并且您在Microsoft SQL Server中看不到这种行为。对于像这样的事情我常说Azure SQL数据库和SQL Server不一样,它们在很多方面都有所不同。