【问题标题】:Testing performance of queries in mysql在mysql中测试查询的性能
【发布时间】:2011-02-14 21:55:18
【问题描述】:

我正在尝试设置一个脚本来测试开发 mysql 服务器上的查询性能。以下是更多详细信息:

  • 我有 root 访问权限
  • 我是唯一访问服务器的用户
  • 最感兴趣的是 InnoDB 性能
  • 我正在优化的查询主要是搜索查询 (SELECT ... LIKE '%xy%')

我想做的是创建可靠的测试环境来测量单个查询的速度,而不依赖于其他变量。

到目前为止,我一直在使用 SQL_NO_CACHE,但有时此类测试的结果也会显示缓存行为 - 第一次运行需要更长的时间执行,而后续运行需要更少的时间。

如果有人能详细解释这种行为,我可能会坚持使用SQL_NO_CACHE;我确实相信这可能是由于文件系统缓存和/或用于执行查询的索引缓存,正如this 帖子所解释的那样。我不清楚 Buffer Pool 和 Key Buffer 何时失效或它们如何干扰测试。

那么,除了重新启动 mysql 服务器之外,您建议如何设置一个可靠的环境来确定一个查询是否比另一个查询执行得更好?

【问题讨论】:

  • 没有任何测试我可以告诉你LIKE '%xy%' 的性能很糟糕。要判断一个查询是否比另一个执行得更好,最好使用 EXPLAIN
  • 是的,我知道这种查询需要做很多比较。问题是查询更复杂,我通常能够以多种方式重写它——每种方式的执行方式不同。我的目标是可靠地衡量性能差异。 (EXPLAIN 是一个很好的建议,我确实使用了它,但除此之外,我还想衡量“真实”的表现)。

标签: performance testing mysql


【解决方案1】:

你可以试试 mysql 工作台,我以为它有一个 sql 语句监视器,所以你可以看到它有多快以及它为什么快

【讨论】:

    【解决方案2】:

    正如链接文章所建议的那样,在测试运行之间使用FLUSH TABLES 尽可能多地重置(尤其是查询缓存)。

    您的测试是否应该考虑到 InnoDB 本身在实际性能期间会具有不同的状态,以便您对多次试验的总体性能感兴趣?如果你想为每次试验重置 InnoDB,你的性能测试有多“真实”?您拒绝的查询,因为它在重新启动后立即表现不佳,可能是 InnoDB 稍微预热后最好的查询。

    如果我是你,我会关注查询优化器所做的工作,而不是 InnoDB 的性能。有很多关于如何调优 InnoDB 的文章,但它有助于启动良好的查询。

    您还可以尝试使用等效的 MyISAM 表来衡量性能,FLUSH TABLES 确实会将您重置到一个几乎相同的起点。

    您是否尝试过完全关闭查询缓存?即使使用 SQL_NO_CACHE,仅启用查询缓存也会产生大约 3% 的损失。

    【讨论】:

      【解决方案3】:

      InnoDB 上的全文查询很慢(LIKE "%query%" statements),您无法优化它们。解决方案多种多样,从将您正在查询的特定表传递给 MyISAM 以便您可以创建全文索引(innoDB 不支持),到将行非规范化为可搜索索引(不推荐),Doctrine ORM 提供了一个如何归档的简单示例: http://www.doctrine-project.org/documentation/manual/1_1/nl/behaviors:core-behaviors:searchable 解决您的问题的“正确”解决方案是使用 Sphinx Search 或 Apache Solr 等解决方案为您使用全文搜索的信息编制索引。

      如前所述,在比较结果时必须考虑缓存状态,已准备好的缓存可提供极高性能的查询。你应该考虑一个特定查询的缓存命中率,即使它是一个昂贵的查询,如果它有 99% 的缓存命中率,那么平均性能会非常高。

      查询的精细调整不是灵丹妙药,您可能会为了优化而增加应用程序的复杂性,而这在生产环境中总体上是可以忽略不计的。

      考虑你的工作量,排查频繁的、性能不佳的查询(使用mysql中的slow_query_log,不要盲目地开始优化查询)。

      【讨论】:

      • 所有与我当前方法一致的建议:开启慢查询日志,考虑 n-gram 引擎,考虑工作负载,我不会忽视生产中的缓存。尽管如此,给定两个给出相同行结果的查询,一旦它们被缓存,它们将执行相同的操作,对吧?所以剩下的就是比较如果它们没有被缓存,它们将如何执行。我很想有一个可靠的方法来回答这个问题。
      • 测试一下。两个并发查询将返回相同的数据集,第二个查询很可能花费更少的时间。我的意思是更少的时间。我的目标是特定查询的性能与应用程序性能不成正比。您不仅应该关注查询的成本,还应该关注它们的频率。频繁调用经过适当缓存的“昂贵”查询平均会变成廉价查询。同样,平均每天调用一次的昂贵查询是考虑成本/频率的廉价查询。
      【解决方案4】:

      您是否考虑过使用Maatkit?我稍微熟悉的其中一项功能是使用 tcpdump 捕获 MySQL 网络数据并使用mk-query-digest 处理转储。此工具允许您显示有关每个查询的一些细粒度的详细信息。但是还有一大堆其他工具可以让查询分析变得更容易。

      【讨论】:

      • Maatkit 在我的测试工具列表中。其他的呢?
      • 好吧,我写的时候可能太困了。我参考了 Maatkit 中的其他命令/工具进行查询分析。
      【解决方案5】:

      假设您无法优化 LIKE 操作本身,您应该尝试优化基本查询,但不尽量减少应检查的行数。

      一些可能对此有用的东西:

      rows EXPLAIN SELECT ... 结果中的列。那么,

      mysql> set profiling=1;
      mysql> select sql_no_cache * from mytable;
       ...
      mysql> show profile;
      +--------------------+----------+
      | Status             | Duration |
      +--------------------+----------+
      | starting           | 0.000063 |
      | Opening tables     | 0.000009 |
      | System lock        | 0.000002 |
      | Table lock         | 0.000005 |
      | init               | 0.000012 |
      | optimizing         | 0.000002 |
      | statistics         | 0.000007 |
      | preparing          | 0.000005 |
      | executing          | 0.000001 |
      | Sending data       | 0.001309 |
      | end                | 0.000003 |
      | query end          | 0.000001 |
      | freeing items      | 0.000016 |
      | logging slow query | 0.000001 |
      | cleaning up        | 0.000001 |
      +--------------------+----------+
      15 rows in set (0.00 sec)
      

      那么,

      mysql> FLUSH STATUS;
      mysql> select sql_no_cache * from mytable;
      ...
      mysql> SHOW SESSION STATUS LIKE 'Select%';
      +------------------------+-------+
      | Variable_name          | Value |
      +------------------------+-------+
      | Select_full_join       | 0     |
      | Select_full_range_join | 0     |
      | Select_range           | 0     |
      | Select_range_check     | 0     |
      | Select_scan            | 1     |
      +------------------------+-------+
      5 rows in set (0.00 sec)
      

      另一个有趣的值是last_query_cost,它显示了优化器估计查询的成本(该值是随机页面读取的次数):

      mysql> SHOW STATUS LIKE 'last_query_cost';
      +-----------------+-------------+
      | Variable_name   | Value       |
      +-----------------+-------------+
      | Last_query_cost | 2635.399000 |
      +-----------------+-------------+
      1 row in set (0.00 sec)
      

      MySQL 文档是您的朋友。

      【讨论】:

      • 需要补充一点,last_query_cost 的输出是有限的。如果您的查询是简单的,它可以工作,子查询或 UNION 将无法通过此检查。
      【解决方案6】:

      引用自 this pageSQL_NO_CACHE 选项会影响查询缓存中查询结果的缓存。如果您的表非常小,则表本身可能已被缓存。由于您只是避免缓存结果而不是表,因此有时您会得到所描述的行为。因此,正如其他帖子中所述,您应该在查询之间使用flush your tables

      【讨论】:

        猜你喜欢
        • 2011-10-14
        • 2012-04-10
        • 1970-01-01
        • 2014-06-22
        • 2011-05-06
        • 2011-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多