Azure SQL数据库 - 查询速度明显慢于Azure VM上的SQL数据库

时间:2017-04-25 15:20:02

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

我们将SQL Server从Azure VM移动到Azure SQL数据库。 Azure VM是DS2_V2,2核,7GB RAM,最大6400 IOPS Azure SQL数据库是标准S3,100 DTU。我在Azure VM上运行Azure DTU计算器工具24小时后选择了这个层 - 它为我建议了这个层。

问题是,与Azure VM上的查询相比,查询(主要是SELECT和UPDATE)现在非常缓慢。我注意到的一件事是,在运行查询时,我访问了Azure门户中监控下的资源利用率图表,并且在任何查询运行期间它都在100%ping。这是否意味着我的意思等级实际上太低了?我希望不会因为下一层次的成本上涨很大。

仅供参考,Azure SQL数据库的架构和数据与Azure VM数据库完全相同,我在迁移后重建了所有索引(包括全文)。

在我的研究中,到目前为止,我已经阅读了从确保我的Azure SQL数据库在Azure上的正确区域(它)到网络延迟(Azure VM上不存在)导致此问题的所有内容。

1 个答案:

答案 0 :(得分:1)

此系统现在作为Azure SQL Server数据库运行了多长时间?据推测,如果它超过几个小时(即一些"生产"查询已经发现它),它就会产生一些有用的统计数据。

分析此问题并确定问题根源将是多管齐下的策略

服务层检查

尝试以下查询,以确定您是否处于正确的服务级别:

-----------------------
---- SERVICE TIER CHECK
-----------------------
-- The following query outputs the fit percentage per resource dimension, based on a threshold of 20%.
-- IF the query below returns values greater than 99.9 for all three resource dimensions, your workload is very likely to fit into the lower performance level.
SELECT 
    (COUNT(end_time) - SUM(CASE WHEN avg_cpu_percent >= 20 THEN 1 ELSE 0 END) * 1.0) / COUNT(end_time) AS 'CPU Fit Percent'
    ,(COUNT(end_time) - SUM(CASE WHEN avg_log_write_percent >= 20 THEN 1 ELSE 0 END) * 1.0) / COUNT(end_time) AS 'Log Write Fit Percent'
    ,(COUNT(end_time) - SUM(CASE WHEN avg_data_io_percent >= 20 THEN 1 ELSE 0 END) * 1.0) / COUNT(end_time) AS 'Physical Data Read Fit Percent'
FROM sys.dm_db_resource_stats

-- Look at how many times your workload reaches 100% and compare it to your database workload SLO.
-- IF the query below returns a value less than 99.9 for any of the three resource dimensions, you should consider either moving to the next higher performance level or use application tuning techniques to reduce the load on the Azure SQL Database.
SELECT 
(COUNT(end_time) - SUM(CASE WHEN avg_cpu_percent >= 100 THEN 1 ELSE 0 END) * 1.0) / COUNT(end_time) AS 'CPU Fit Percent'
,(COUNT(end_time) - SUM(CASE WHEN avg_log_write_percent >= 100 THEN 1 ELSE 0 END) * 1.0) / COUNT(end_time) AS 'Log Write Fit Percent'
,(COUNT(end_time) - SUM(CASE WHEN avg_data_io_percent >= 100 THEN 1 ELSE 0 END) * 1.0) / COUNT(end_time) AS 'Physical Data Read Fit Percent'
FROM sys.dm_db_resource_stats

资源消耗级别

检查资源消耗也很有用,您可以使用以下查询来执行此操作。这将报告DTU消耗和IO等内容。

-----------------
-- Resource Usage
-----------------
select *
from sys.dm_db_resource_stats 
order by end_time desc

索引

还值得快速检查您是否缺少索引或是否有一些现有索引妨碍了。

  

缺少的索引查询是一个doozy,但应该采取一些盐。我通常将其视为关于如何使用数据库的建议,并且我自己判断要添加哪些索引以及如何添加。例如,作为一般经验法则,所有外键都应该有非聚集索引,以方便他们参与的不可避免的JOIN。

--------------------
-- Find poor indexes
--------------------
DECLARE @dbid int
SELECT @dbid = db_id()

SELECT 'Table Name' = object_name(s.object_id), 'Index Name' =i.name, i.index_id,
        'Total Writes' =  user_updates, 'Total Reads' = user_seeks + user_scans + user_lookups,
        'Difference' = user_updates - (user_seeks + user_scans + user_lookups)
FROM sys.dm_db_index_usage_stats AS s 
INNER JOIN sys.indexes AS i
ON s.object_id = i.object_id
AND i.index_id = s.index_id
WHERE objectproperty(s.object_id,'IsUserTable') = 1
AND s.database_id = @dbid
AND user_updates > (user_seeks + user_scans + user_lookups)
ORDER BY 'Difference' DESC, 'Total Writes' DESC, 'Total Reads' ASC;

------------------
-- Missing Indexes
------------------
declare @improvementMeasure int = 100

SELECT
CONVERT (decimal (28,1), 
migs.avg_total_user_cost * 
migs.avg_user_impact * 
(migs.user_seeks + migs.user_scans)) 
AS improvement_measure, 
OBJECT_NAME(mid.object_id, mid.database_id) as table_name,
  mid.equality_columns as index_column,
  mid.inequality_columns,
  mid.included_columns as include_columns, 
'CREATE INDEX IX_' + 
OBJECT_NAME(mid.object_id, mid.database_id) + 
'_' + 
REPLACE(REPLACE(mid.equality_columns, '[', ''), ']', '') + 
' ON ' + 
mid.statement + 
' (' + ISNULL (mid.equality_columns,'') + 
CASE WHEN mid.equality_columns IS NOT NULL 
AND mid.inequality_columns IS NOT NULL 
THEN ',' 
ELSE '' 
END + ISNULL (mid.inequality_columns, '') + 
')' + 
ISNULL (' INCLUDE (' + mid.included_columns + ')',
'') AS create_index_statement, 
migs.user_seeks,
migs.unique_compiles,
migs.avg_user_impact,
migs.avg_total_user_cost

FROM sys.dm_db_missing_index_groups mig
INNER JOIN sys.dm_db_missing_index_group_stats migs 
ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details mid 
ON mig.index_handle = mid.index_handle
WHERE CONVERT (decimal (28,1), 
migs.avg_total_user_cost * 
migs.avg_user_impact * 
(migs.user_seeks + migs.user_scans)) > @improvementMeasure
ORDER BY migs.avg_total_user_cost * 
migs.avg_user_impact * 
(migs.user_seeks + migs.user_scans) DESC

维护

还应设置维护计划,以便您定期重建索引和统计信息。遗憾的是,Azure SQL环境中没有SQL代理。但是,Powershell和Azure functionAzure WebJob可以帮助您安排和执行此操作。对于我们的本地和天蓝色服务器,我们每周都会这样做。

  

请注意,只有拥有预先存在的App Service才能在其中运行,WebJob只会有所帮助。

对于帮助您进行索引和统计信息维护的脚本,请检查Ola Hallengren's脚本产品。