如何构建MySQL以便我可以对查询/索引的性能进行基准测试?

时间:2015-02-13 00:44:29

标签: mysql caching indexing buffer

我有一个2500万行的MySQL 5.6表。我正在改进表格上的索引。当我第一次执行简单查询时需要10秒,并且每次后续时间仅需0.1秒。当我过滤不同的密钥时,执行时间会回升到10秒。

这种行为告诉我,我在后续查询中获得了缓存和缓冲的好处。我理解MySQL实现了QUERY CACHE,但RESET QUERY CACHE之后的后续查询仍然需要0.1秒。

我理想的是:

  • 调用查询几次以获得基线平均执行时间(即10个实例上的10.38秒)。
  • 优化我的表索引设计
  • 调用查询几次以获得新的平均执行时间(即10个实例的7.91秒)。
  • 决定是保留还是放弃改进

如何启动MySQL以便我可以在没有缓冲,缓存,预取等优势的情况下对查询/索引的性能进行基准测试?

6 个答案:

答案 0 :(得分:1)

MySQL有一个名为performance_schema的数据库默认值。它对你有用。如果您的服务器上不存在,请尝试启用此功能。以下是http://dev.mysql.com/doc/refman/5.5/en/performance-schema-quick-start.html

的说明

答案 1 :(得分:1)

执行摘要:

  • 关闭查询缓存;
  • 设置innodb_buffer_pool_size;
  • 使用第二个时间运行测试查询两次;
  • 不要试图包含所有I / O;这是不现实的。

详细说明:

首先,您需要了解“查询缓存”是什么和不是什么。这是一个通常最好关闭的kludge。它记录确切的查询(字节为字节)及其结果集,但只要发生写入就会被清除。 (我过度简化了它。)因此,要么将其关闭,要么使用SELECT SQL_NO_CACHE ...以防止混淆基准。可以使用QC的典型查询大约需要1毫秒,无论它有多复杂。那是一个有用的指标。​​

现在,让我们进入'真实'缓存 - InnoDB的“缓冲池”。 (我假设您使用的是InnoDB,而不是MyISAM。)该缓存应该是可用内存的70%左右(但如果您未在my.cnf中设置innodb_buffer_pool_size,则可能不是这样)。它缓存构成InnoDB表的的读写操作。当您从表中读取记录时,InnoDB需要从您正在使用的索引中找到一些块,以及包含数据的块。从磁盘读取块需要10ms。如果最近查看了这些,那么它们很可能在缓冲池中。通常,未缓存和缓存之间的差异为10倍。 (你看到100倍的加速,所以我可能不会解释所有内容。)

在测试给定查询的速度时,我喜欢运行它两次。它第一次将获取缓冲池中尚未存在的任何块,然后它将仅使用CPU工作来执行它。第二次运行只是CPU(除非它扫描25M行,它们不适合缓冲池)。

获取I / O的时间变得更加复杂,而且通常没有必要。我说“没必要”,因为比较显示CPU时间差异的两次运行通常意味着I / O也可能同样不同。此外,定时I / O是不现实的,因为在“生产”中缓冲池中充满了缓存的内容,因此许多查询不需要访问磁盘。

如果您想进一步讨论您的应用,我们可以讨论PARTITIONing(不一定是有益的),数据仓库(和速度技术)和/或UUID(坏)等。

答案 2 :(得分:1)

您必须使用SQL_NO_CACHE函数才能在每个查询的基础上禁用MySQL查询缓存

 SELECT SQL_NO_CACHE <columns> FROM table WHERE <condition>;

您必须使用的一件事是EXPLAIN命令,以便了解您的查询中使用了哪些索引,或者不是:

 EXPLAIN SELECT SQL_NO_CACHE <columns> FROM table WHERE <condition>;

答案 3 :(得分:1)

MySQL有更强大的方法来判断查询性能,时间有所帮助,但解释提供了更多的洞察力(我相信它会强制查询运行未缓存,因为其他数据库为执行数字执行此操作,但我无法找到参考)。

如果您对数据库进行索引更改,那么您首先要对索引进行优化。这会更新统计信息表,告诉MySQL如何构建解释计划。语法只是:

OPTIMIZE TABLE_NAME

加上一些轻读:http://dev.mysql.com/doc/refman/5.1/en/optimize-table.html

然后你想要运行一个解释计划来告诉你MySQL对你的指数做了什么。如果你使用永远不会被使用的索引,那么你只是放慢了插入速度。如何运行:

EXPLAIN YOUR_QUERY

这是MySQL的一个例子

mysql> EXPLAIN EXTENDED
-> SELECT t1.a, t1.a IN (SELECT t2.a FROM t2) FROM t1\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: t1
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 4
        Extra: Using index
*************************** 2. row ***************************
           id: 2
  select_type: DEPENDENT SUBQUERY
        table: t2
         type: index_subquery
possible_keys: a
          key: a
      key_len: 5
          ref: func
         rows: 2
        Extra: Using index
2 rows in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: select `test`.`t1`.`a` AS `a`,
         <in_optimizer>(`test`.`t1`.`a`,
         <exists>(<index_lookup>(<cache>(`test`.`t1`.`a`)
         in t2 on a checking NULL having
         <is_not_null_test>(`test`.`t2`.`a`)))) AS `t1.a
         IN (SELECT t2.a FROM t2)` from `test`.`t1`
1 row in set (0.00 sec)

注意rows字段,这会告诉你MySQL必须处理多少条记录才能得到答案。由于这涉及内部选择,因此&#34;查询成本&#34;应该是~4 + 2,这是您可以与不同查询进行比较的相对数字。然而,如果它是一个连接,那么&#34;查询成本&#34;将是~4x2。您可以考虑为您的成本等式键入一个修饰符类型,但对于您正在执行的任何操作,最简单的方法就是采用最佳类型。在下面的博客文章链接中有关于类型的非常好的解释。

更多解释计划阅读:http://dev.mysql.com/doc/refman/5.5/en/execution-plan-information.html

一个非常好的解释计划解释:http://www.sitepoint.com/using-explain-to-write-better-mysql-queries/

答案 4 :(得分:1)

您遇到的是热门和冷门查询/数据库之间的区别。热查询是访问已经在内存中的所需数据的查询,其中冷(查询)需要将其数据加载到存储器中。这就是为什么在内存中的数据缓存包含提供大多数请求所需的数据之前,你所说的大数据库是一个预热阶段。

当然它可以是查询缓存,但也可能是磁盘缓存。取决于您正在使用的内存。

接下来的问题是你要对数据库做什么。通常今天你很有可能通过记忆解决这个问题。 TB的内存只需10k。所以谁在乎。

也可以使用说明。数据库通常都是关于您从数据库中登录的页面以及内存数据用于填充您的请求的方式。

EXPLAIN是正确的使用方法。查询缓存通常可以关闭。用处不大。如果结果是静态的,那么很可能您仍然使用Web缓存或站点缓存。

同时检查正在使用的indizes。通常你会找到缓解疼痛的方法。

答案 5 :(得分:1)

当我这样做时,我使用了SELECT SQL_NO_CACHE

或者您可以每次对查询进行空格更改。查询缓存通过逐字查询字符串进行索引,任何更改(包括额外空格)都显示为不同的查询。