【问题标题】:SQL Azure Query Performance - Terribly Slow Even With Tuned QueriesSQL Azure 查询性能 - 即使使用经过优化的查询也非常慢
【发布时间】:2011-07-27 21:29:03
【问题描述】:

这是一个依赖于两个非聚集索引的基本查询:

SELECT cc.categoryid, count(*) from company c
INNER JOIN companycategory cc on cc.companyid = c.id
WHERE c.placeid like 'ca_%'
GROUP BY cc.categoryid order by count(*) desc

当完全相同的数据库托管在 SQL Server 2008 上时,几乎在任何硬件上,这都会返回

DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS

...在传统 SQL 上,这仍然会在大约 1 秒内返回。

在 Azure 上,每次返回大约需要 3.5 秒。

一些articles 似乎表明人们普遍对SQL Azure 中的查询性能感到满意。然而,这是一个基本场景,其中“明显”的调整已经用尽,并且没有网络延迟问题可言。在处理大型表时,它真的很慢(companycategroy 有 120 万条记录,places 有 7.5K)。

数据库总大小不超过 4GB。选择“Web”版本与“Enterprise”版本似乎也没有太大区别。

我错过了什么?

这只是一个基本示例,只有更复杂的查询会变得更糟,所有查询都经过 reviewed 调整,并且在本地运行良好。

这是执行计划:

  |--Sort(ORDER BY:([Expr1004] DESC))
       |--Compute Scalar(DEFINE:([Expr1004]=CONVERT_IMPLICIT(int,[Expr1007],0)))
            |--Hash Match(Aggregate, HASH:([cc].[CategoryId]), RESIDUAL:([XX].[dbo].[CompanyCategory].[CategoryId] as [cc].[CategoryId] = [XX].[dbo].[CompanyCategory].[CategoryId] as [cc].[CategoryId]) DEFINE:([Expr1007]=COUNT(*)))
                 |--Hash Match(Inner Join, HASH:([c].[Id])=([cc].[CompanyId]))
                      |--Index Scan(OBJECT:([XX].[dbo].[Company].[IX_Company_PlaceId] AS [c]),  WHERE:([XX].[dbo].[Company].[PlaceId] as [c].[PlaceId] like N'ca_%'))
                      |--Index Scan(OBJECT:([XX].[dbo].[CompanyCategory].[IX_CompanyCategory_CompanyId] AS [cc]))

以下是统计数据:

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 14 ms, elapsed time = 14 ms.

(789 row(s) affected)

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 'CompanyCategory'. Scan count 1, logical reads 5183, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Company'. Scan count 1, logical reads 8710, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 3328 ms,  elapsed time = 3299 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

索引定义如下:

CREATE NONCLUSTERED INDEX [IX_Company_PlaceId] ON [dbo].[Company] 
(
    [PlaceId] 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)
GO

CREATE NONCLUSTERED INDEX [IX_CompanyCategory_CompanyId] ON [dbo].[CompanyCategory] 
(
    [CompanyId] 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)
GO

ALTER TABLE [dbo].[Company] ADD  CONSTRAINT [PK_Company_Id] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON)
GO

【问题讨论】:

  • 能否在Azure上发布查询的文本查询计划和统计信息?请运行SET STATISTICS IO ON SET STATISTICS TIME ON GO SET SHOWPLAN_TEXT ON GO SELECT …
  • 我们当然可以查看查询计划...
  • 我们在 Azure 上有执行计划。我们应该看到他的本地数据库运行速度如此之快。
  • @todda.speot.is,我相信 Azure 默认具有自动统计功能。 Company.Id 是一个整数(代理键),Place.Id 是一个 varchar(50) 自然键。
  • @Steve:我们在这里看不到集群搜索。如果id 是聚集的PK,则它会被任何其他索引隐式包含。

标签: sql-server azure azure-sql-database


【解决方案1】:

他们似乎为您的查询使用了一个 CPU 核心,而在您的机器上查询可能并行化(查询使用的所有操作都并行化)。

但是,由于某种原因,索引扫描用于LIKE 谓词,而索引查找就足够了。

请尝试使用这个显式条件而不是LIKE

c.placeid >= 'ca'
AND c.placeid < 'cb'

并查看它是否将计划更改为IX_CompanyPlaceId 上的Index Seek

【讨论】:

  • 感谢刚刚尝试过,但它仍在生成索引扫描。
  • @Nariman:请运行SELECT COUNT(*), SUM(CASE WHEN placeid LIKE 'ca%' THEN 1 END) FROM company
  • 大概就是这样。目前,这些数字相匹配,因为所有公司都植根于同一个国家(并非总是如此)。但是,即使我将其限定为一个地区/州(即像 'ca_on%',代表 120 万条记录的 30%),我仍然看到 Azure 的延迟,尽管没有那么大。正如您所建议的,我确实看到查询在本地而不是在 Azure 上并行化。
  • @Nariman:以防万一:_LIKE 条件中的通配符,请使用LIKE 'ca[_]%' 匹配文字下划线。 Index scan,不过,这里真的很奇怪:如果索引无论如何都要使用,绝对没有理由不去寻找它。您能否发布索引定义?
  • 发布了索引定义。应用所有更改(使用 [_]、合并连接、使用 LIKE 'ca_on%' 仅匹配 120 万条记录的 30%)后,清除缓存缓冲区的本地部署仍然比 SQL Azure 至少高出 2 倍。
【解决方案2】:

只有几件事:

  • Azure 上的统计数据是最新的吗?我对 120 万行表的哈希匹配有点警惕
  • Azure 有自动统计吗?如果没有,您的本地数据库可能包含更多 SQL Azure 无法用来选择最佳查询计划的信息
  • 索引c.placeid获取一些统计数据
  • 为什么c.placeid 是一个字符串?这是否会延续到companyidc.id?我认为这就是您使用哈希匹配的原因 - 尝试加入整数代理键。

【讨论】:

  • 谢谢。合并连接将其降低了整整一秒至 2.3 秒,好得多,但仍无法与本地相比。
【解决方案3】:

我在 Azure SQL 数据库索引维护上发布此链接,因为索引维护仍然需要帮助。

https://blogs.msdn.microsoft.com/azuresqldbsupport/2016/07/03/how-to-maintain-azure-sql-indexes-and-statistics/

我们使用运行手册在不同弹性池上的 350 多个数据库中执行索引维护。希望其他人能像我们一样发现这些信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-02
    • 1970-01-01
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    相关资源
    最近更新 更多