为什么 运行 SQL Azure 上的查询要慢得多?
Why is running a query on SQL Azure so much slower?
我在 Azure 上创建了一个试用帐户,并从 SmarterAsp
部署了我的数据库。
当我 运行 在 SmarterAsp\MyDatabase
上进行数据透视查询时,结果在 2 秒 后出现。
但是,运行在 Azure\MyDatabase
上执行相同的查询花费了 94 秒 。
我使用 SQL Server 2014 Management Studio(试用版)连接到服务器并 运行 查询。
这种速度差异是因为我的账户是试用账户吗?
我的问题的一些相关信息
查询是:
ALTER procedure [dbo].[Pivot_Per_Day]
@iyear int,
@imonth int,
@iddepartment int
as
declare @columnName Nvarchar(max) = ''
declare @sql Nvarchar(max) =''
select @columnName += quotename(iDay) + ','
from (
Select day(idate) as iDay
from kpivalues where year(idate)=@iyear and month(idate)=@imonth
group by idate
)x
set @columnName=left(@columnName,len(@columnName)-1)
set @sql ='
Select * from (
select kpiname, target, ivalues, convert(decimal(18,2),day(idate)) as iDay
from kpi
inner join kpivalues on kpivalues.idkpi=kpi.idkpi
inner join kpitarget on kpitarget.idkpi=kpi.idkpi
inner join departmentbscs on departmentbscs.idkpi=kpi.idkpi
where iddepartment='+convert(nvarchar(max),@iddepartment)+'
group by kpiname,target, ivalues,idate)x
pivot
(
avg(ivalues)
for iDay in (' + @columnName + ')
) p'
execute sp_executesql @sql
运行 这个在 3 个不同服务器上的查询在我的枢轴 table 出现在屏幕上之前的运行时间方面给了我不同的结果:
Azure - 运行时间 = 100.165 秒
Smarterasp.net - 经过时间 = 2.449 秒
LocalServer - 运行时间 = 1.716 秒
关于我在 Azure 上的试用帐户,我的主要目标是检查在像上面那样 运行ning 存储过程时我是否会有比 Smarter 更快的速度。
我为我的数据库选择服务层级 - 基本、性能级别 - 基本 (5DTU) 和最大。大小 2GB。
我的数据库有16个tables,1个table有145284行,数据库大小为11mb。它是我的应用程序的测试数据库。
我的问题是:
- 我能做些什么来优化这个查询 (sp)?
- 是否推荐将 Azure 用于小型数据库 (100mb-1Gb)?我的意思是性能与成本!
根据您的输入得出的结论:
- 我对查询进行了建议的更改,性能提高了 50% 以上 - 谢谢 Remus
- 我在 Azure S2 上测试了我的查询,更新查询的运行时间为 11 秒。
我再次测试了我在 P1 上的查询,经过的时间是 0.5 秒:)
SmarterASP 上的相同更新查询的运行时间为 0.8 秒。
现在我很清楚 Azure 中的层是什么以及拥有一个非常好的查询是多么重要(我什至了解什么是索引和他的advantage/disadvantage)
谢谢大家,
卢锡安
(更新:原来的问题已经改成还问如何优化查询——这也是个好问题。原来的问题是为什么差异 这就是这个答案的内容)。
单个查询的性能受性能层的影响很大。我知道文档暗示层级与负载有关,但严格来说并非如此。
我会重新运行你的测试,以 S2 数据库为起点,然后从那里开始。
试用订阅本身不会影响性能,但使用免费帐户,您可能使用的是 B 级别,这对任何真实的东西都没有真正的用处 - 当然不是用于需要 2 秒才能完成的查询 运行 本地。
即使在 S1 和 S2 之间移动,单个查询的性能也会有显着差异。
如果你想做实验,请记住你需要支付 "any part of a day" 一天的费用,这对 S 级来说可能没问题,但在测试 P 级时要小心。
用于背景;当 Azure 去年推出新层级时,他们更改了 SQL 的托管模型。过去,许多数据库 运行 在共享 sqlserver.exe 上。在新模型中,每个数据库有效地在资源受限的沙箱中获得自己的 sqlserver.exe 和 运行。这就是他们控制 "DTU usage" 的方式,但也会影响总体性能。
这首先是性能问题。您正在处理您的部分性能不佳的代码,您必须确定瓶颈并解决它。我现在说的是糟糕的 2 秒 性能。请遵循 How to analyse SQL Server performance 中的指南。一旦您让此查询执行本地可接受的 Web 应用程序(少于 5 毫秒),您就可以提出将其移植到 Azure SQL 数据库的问题。现在您的试用帐户只是突出了现有的低效率。
更新后
...
@iddepartment int
...
iddepartment='+convert(nvarchar(max),@iddepartment)+'
...
那是什么? iddepartment
列是 int
还是 nvarchar
?为什么要使用 (max)
?
这是你应该做的:
- 在内部动态SQL
中参数化@iddepartment
- 停止进行
nvarchar(max)
转换。使 iddepartment
和 @iddertment
类型匹配
- 确保
iddepartment
和所有 idkpi
上的索引
下面是如何参数化内部 SQL:
set @sql =N'
Select * from (
select kpiname, target, ivalues, convert(decimal(18,2),day(idate)) as iDay
from kpi
inner join kpivalues on kpivalues.idkpi=kpi.idkpi
inner join kpitarget on kpitarget.idkpi=kpi.idkpi
inner join departmentbscs on departmentbscs.idkpi=kpi.idkpi
where iddepartment=@iddepartment
group by kpiname,target, ivalues,idate)x
pivot
(
avg(ivalues)
for iDay in (' +@columnName + N')
) p'
execute sp_executesql @sql, N'@iddepartment INT', @iddepartment;
到目前为止,覆盖索引是最重要的修复。这显然需要比这里提供的更多的信息。阅读 Designing Indexes 包括所有子章节。
作为更笼统的评论:这种查询比行存储更适合 columnstores,尽管我认为数据大小基本上很小。 Azure SQL DB 支持可更新的聚集列存储索引,您可以在预期数据量很大的情况下进行试验。他们确实需要 Enterprise/Development 在本地框上,是的。
这与您的帐户是试用版无关,这是因为您选择的性能级别较低。
在其他服务 (SmarterAsp) 和 运行 本地实例中,您可能没有性能限制而是大小限制。
在这一点上,不可能将 DTU 的实际含义放在一起/哪种 DTU 编号与安装在本地计算机或任何其他托管服务提供商中的 Sql 服务器相关联。
但是,对此进行了一些很好的分析 (https://cbailiss.wordpress.com/2014/09/16/performance-in-new-azure-sql-database-performance-tiers/),但没有正式的分析。
我在 Azure 上创建了一个试用帐户,并从 SmarterAsp
部署了我的数据库。
当我 运行 在 SmarterAsp\MyDatabase
上进行数据透视查询时,结果在 2 秒 后出现。
但是,运行在 Azure\MyDatabase
上执行相同的查询花费了 94 秒 。
我使用 SQL Server 2014 Management Studio(试用版)连接到服务器并 运行 查询。
这种速度差异是因为我的账户是试用账户吗?
我的问题的一些相关信息
查询是:
ALTER procedure [dbo].[Pivot_Per_Day]
@iyear int,
@imonth int,
@iddepartment int
as
declare @columnName Nvarchar(max) = ''
declare @sql Nvarchar(max) =''
select @columnName += quotename(iDay) + ','
from (
Select day(idate) as iDay
from kpivalues where year(idate)=@iyear and month(idate)=@imonth
group by idate
)x
set @columnName=left(@columnName,len(@columnName)-1)
set @sql ='
Select * from (
select kpiname, target, ivalues, convert(decimal(18,2),day(idate)) as iDay
from kpi
inner join kpivalues on kpivalues.idkpi=kpi.idkpi
inner join kpitarget on kpitarget.idkpi=kpi.idkpi
inner join departmentbscs on departmentbscs.idkpi=kpi.idkpi
where iddepartment='+convert(nvarchar(max),@iddepartment)+'
group by kpiname,target, ivalues,idate)x
pivot
(
avg(ivalues)
for iDay in (' + @columnName + ')
) p'
execute sp_executesql @sql
运行 这个在 3 个不同服务器上的查询在我的枢轴 table 出现在屏幕上之前的运行时间方面给了我不同的结果:
Azure - 运行时间 = 100.165 秒
Smarterasp.net - 经过时间 = 2.449 秒
LocalServer - 运行时间 = 1.716 秒
关于我在 Azure 上的试用帐户,我的主要目标是检查在像上面那样 运行ning 存储过程时我是否会有比 Smarter 更快的速度。 我为我的数据库选择服务层级 - 基本、性能级别 - 基本 (5DTU) 和最大。大小 2GB。
我的数据库有16个tables,1个table有145284行,数据库大小为11mb。它是我的应用程序的测试数据库。
我的问题是:
- 我能做些什么来优化这个查询 (sp)?
- 是否推荐将 Azure 用于小型数据库 (100mb-1Gb)?我的意思是性能与成本!
根据您的输入得出的结论:
- 我对查询进行了建议的更改,性能提高了 50% 以上 - 谢谢 Remus
- 我在 Azure S2 上测试了我的查询,更新查询的运行时间为 11 秒。
我再次测试了我在 P1 上的查询,经过的时间是 0.5 秒:)
SmarterASP 上的相同更新查询的运行时间为 0.8 秒。
现在我很清楚 Azure 中的层是什么以及拥有一个非常好的查询是多么重要(我什至了解什么是索引和他的advantage/disadvantage)
谢谢大家, 卢锡安
(更新:原来的问题已经改成还问如何优化查询——这也是个好问题。原来的问题是为什么差异 这就是这个答案的内容)。
单个查询的性能受性能层的影响很大。我知道文档暗示层级与负载有关,但严格来说并非如此。
我会重新运行你的测试,以 S2 数据库为起点,然后从那里开始。
试用订阅本身不会影响性能,但使用免费帐户,您可能使用的是 B 级别,这对任何真实的东西都没有真正的用处 - 当然不是用于需要 2 秒才能完成的查询 运行 本地。
即使在 S1 和 S2 之间移动,单个查询的性能也会有显着差异。 如果你想做实验,请记住你需要支付 "any part of a day" 一天的费用,这对 S 级来说可能没问题,但在测试 P 级时要小心。
用于背景;当 Azure 去年推出新层级时,他们更改了 SQL 的托管模型。过去,许多数据库 运行 在共享 sqlserver.exe 上。在新模型中,每个数据库有效地在资源受限的沙箱中获得自己的 sqlserver.exe 和 运行。这就是他们控制 "DTU usage" 的方式,但也会影响总体性能。
这首先是性能问题。您正在处理您的部分性能不佳的代码,您必须确定瓶颈并解决它。我现在说的是糟糕的 2 秒 性能。请遵循 How to analyse SQL Server performance 中的指南。一旦您让此查询执行本地可接受的 Web 应用程序(少于 5 毫秒),您就可以提出将其移植到 Azure SQL 数据库的问题。现在您的试用帐户只是突出了现有的低效率。
更新后
...
@iddepartment int
...
iddepartment='+convert(nvarchar(max),@iddepartment)+'
...
那是什么? iddepartment
列是 int
还是 nvarchar
?为什么要使用 (max)
?
这是你应该做的:
- 在内部动态SQL 中参数化
- 停止进行
nvarchar(max)
转换。使iddepartment
和@iddertment
类型匹配 - 确保
iddepartment
和所有idkpi
上的索引
@iddepartment
下面是如何参数化内部 SQL:
set @sql =N'
Select * from (
select kpiname, target, ivalues, convert(decimal(18,2),day(idate)) as iDay
from kpi
inner join kpivalues on kpivalues.idkpi=kpi.idkpi
inner join kpitarget on kpitarget.idkpi=kpi.idkpi
inner join departmentbscs on departmentbscs.idkpi=kpi.idkpi
where iddepartment=@iddepartment
group by kpiname,target, ivalues,idate)x
pivot
(
avg(ivalues)
for iDay in (' +@columnName + N')
) p'
execute sp_executesql @sql, N'@iddepartment INT', @iddepartment;
到目前为止,覆盖索引是最重要的修复。这显然需要比这里提供的更多的信息。阅读 Designing Indexes 包括所有子章节。
作为更笼统的评论:这种查询比行存储更适合 columnstores,尽管我认为数据大小基本上很小。 Azure SQL DB 支持可更新的聚集列存储索引,您可以在预期数据量很大的情况下进行试验。他们确实需要 Enterprise/Development 在本地框上,是的。
这与您的帐户是试用版无关,这是因为您选择的性能级别较低。
在其他服务 (SmarterAsp) 和 运行 本地实例中,您可能没有性能限制而是大小限制。
在这一点上,不可能将 DTU 的实际含义放在一起/哪种 DTU 编号与安装在本地计算机或任何其他托管服务提供商中的 Sql 服务器相关联。
但是,对此进行了一些很好的分析 (https://cbailiss.wordpress.com/2014/09/16/performance-in-new-azure-sql-database-performance-tiers/),但没有正式的分析。