【问题标题】:Simple select count(id) uses 100% of Azure SQL DTUs简单选择计数 (id) 使用 100% 的 Azure SQL DTU
【发布时间】:2014-09-27 09:05:16
【问题描述】:

这从this question 开始,但现在似乎更适合专门询问,因为我意识到这是一个与 DTU 相关的问题。

基本上,运行:

select count(id) from mytable

编辑:添加 where 子句似乎没有帮助。

运行需要 8 到 30 分钟(而在 SQL Server 的本地副本上执行相同的查询大约需要 4 )。

下面是我运行此查询时 Azure 门户中的 MONITOR 选项卡的屏幕截图。请注意,我在大约一周未接触数据库后执行此操作,Azure 报告我只使用了 1% 的 DTU。

一些额外的东西:

  • 在此特定测试中,查询运行时间为 08:27。
  • 在运行时,上图实际上显示 DTU 线在一段时间内处于 100%。
  • 数据库配置为具有 S1 性能级别的标准服务层。
  • 数据库大约 3.3GB,这是最大的表(计数返回大约 2,000,000)。

我很感激这可能只是我有限的理解,但如果有人能澄清这是否真的是预期的行为(即一个简单的计数需要很长时间才能运行并最大化我的 DTU),那将不胜感激。

【问题讨论】:

  • 原始问题中的答案已经涵盖了发生的情况。 “简单”计数实际上是人为的、昂贵的并且必须扫描整个表。 不要那样做。如果您有一个使用索引字段的 WHERE 子句,则优化器将使用 Index Seek 操作,从而获得更好的性能。在计算总数之前,Seek 会读取索引 B-Tree 以找到匹配的行(即,IO 少得多,速度更快)。如果您使用具有高选择性的字段,您将不得不阅读更少的索引页。
  • 只是 FTR,'简单' 计数不是人为的 - 这是我需要使用/不使用各种 where 子句的情况。
  • 你有没有得到令人满意的答案,为什么会发生这种情况?我在 S2 (50 DTU) 上看到了同样的情况,它在一个 127GB 的数据库中使用了一个包含 5.5 亿行的表,并且 count(1) 需要将近一个小时。
  • 我在批量导入这些数据时也看到了类似的情况。我使用了 freebcp 实用程序,速度非常低,大约每秒 5000 行。我把它写成了实用程序的低效率,但我现在检查了一下,批量插入也使 DTU 达到最大值。
  • 这个 DTU 限制对我来说没有意义:您关于此主题的其他问题中的一个 cmets 表明 P1 类似于四核 12GB RAM 服务器,但 P1 只有 125 DTU - 一个因素2.5 从我所拥有的,这还不足以让计数达到应该在几秒钟的范围内。

标签: azure azure-sql-database sqlperformance


【解决方案1】:

从您previous question 中的查询统计数据我们可以看到:

300ms CPU time
8000 physical reads

8:30 大约是 500 秒。我们当然不受 CPU 限制。超过 500 秒的 300 毫秒 CPU 几乎没有利用率。我们每秒获得 16 次物理读取。这远远低于任何物理磁盘所能提供的。此外,物理 IO 的存在表明该表没有完全缓存。

我会说你被限制了。 S1 corresponds

每分钟 934 笔交易

关于交易的一些定义。那是大约 15 转/秒。也许您达到了每个事务一个物理 IO 的限制?! 15 和 16 是可疑的相似数字。

通过将实例升级到更高的比例因子来测试这个理论。 You might find that SQL Azure Database cannot deliver the performance you want at an acceptable price.

您还应该发现,重复扫描 一半 表会导致快速查询,因为分配的缓冲池似乎适合大部分表(而不是全部)。

【讨论】:

  • 感谢您的分析。我没有时间验证这一点(如果/当我这样做时,我会将其标记为正确),但我认为您可能就在这里 - 我只是惊讶于一个简单的计数......哪里可以占用这么多 DTU。不过,我对 SQL Server 的这一方面并不是非常有经验,因此对许多人来说可能很明显这是一项非常昂贵的操作。
  • 定义“昂贵”。它需要扫描表(或它的某些索引)。我认为这会产生与表大小成比例的 IO。它产生的 CPU 负载可以忽略不计。
  • 我想我的意思是在 DTU 方面很昂贵,这基本上是您使用不同 Azure SQL 级别所支付的费用。
  • Th count() 与此查询的开销无关。超出分配的缓冲池内存是根本原因。任何这样做的查询都有完全相同的问题。您可以在一半大的桌子上运行 count(),它会在 150 毫秒的 CPU 时间内运行,并且可能与挂钟时间差不多。
【解决方案2】:

我遇到了同样的问题。在表上使用全扫描更新统计信息解决了它:

update statistics mytable with fullscan

【讨论】:

    【解决方案3】:

    选择计数

    如果有可用的并且是最新的,则应该执行聚集索引扫描。 Azure SQL 应自动更新统计信息,但如果索引完全过期,则不会自动重建索引。

    如果该表上有很多 INSERT/UPDATE/DELETE 流量,我建议每隔一段时间手动重建索引。

    http://blogs.msdn.com/b/dilkushp/archive/2013/07/28/fragmentation-in-sql-azure.aspx

    然后发帖了解更多信息

    SQL Azure and Indexes

    【讨论】:

    • 谢谢,我一直在重建索引,我想我正在使用您链接到的 MSDN 文章中的 SQL。该表似乎有一个 0.2% 碎片化的 CLUSTERED INDEX。据我所知,这不是问题。
    • @chrisb 您正在使用一个人为的示例,保证会导致昂贵的读取(以 IO 术语)。它代表真实的查询。如果您在 WHERE 子句中使用单个索引字段,性能会快得多
    • @chrisb 我认为这是我们需要查看统计数据和执行计划的地方。这是如何打开它们的基本指南:solidq.com/tuning-sql-azure-databases-part-1
    • @b0rg 检查原始问题,这已经涵盖。您还可以在那里找到统计数据。我认为 OP 应该尝试衡量一个实际的查询,而不是保证扫描表的查询
    • 感谢您的回复,一些事情。 1)这个例子真的那么做作吗?我需要定期运行此查询或类似查询,并且添加 where 子句无济于事。 2)在我的笔记本电脑上运行相同的查询需要
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    • 2016-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多