iva*_*van 5 mysql innodb performance query-performance
使用 InnoDB 运行 MySQL:
我有一个SELECT wide_table.*要优化的查询,SELECT wide_table.id因为这就是调用代码所需的全部内容。对其进行测试,我发现 with 的执行时间*比 with 快id(尽管“精制”版本通过网络传输结果的时间更快)。
为什么会这样?
查询(更改名称以保护无辜者)是:
SELECT
`things`.*
FROM
`things`
WHERE
`things`.`active` = 1
AND (owner_id IS NOT NULL
AND owner_id > 0)
AND ((`things`.`status` IN (0 , 1)
OR `things`.`status` IS NULL))
AND (date < '2015-07-11 00:00:00');
Run Code Online (Sandbox Code Playgroud)
有一个复合索引active并且date,这是在两个版本中使用。
作为参考,输出SHOW CREATE TABLE(省略了不相关的列):
CREATE TABLE `things` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`active` tinyint(1) DEFAULT '0',
`date` datetime DEFAULT NULL,
`owner_id` int(11) DEFAULT '0',
`status` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_things_on_active_and_date` (`active`,`date`),
KEY `index_things_on_date` (`date`),
KEY `index_things_on_owner_id` (`owner_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1862 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Run Code Online (Sandbox Code Playgroud)
玩了一段时间后,我发现比较受到对查询施加的限制的影响。使用大限制(>200)时,该*版本报告更快的执行时间。随着限制降低 <200,id版本占上风。仍然不知道该怎么做...
EXPLAIN在两个版本的查询上运行会产生相同的输出,带有 select_type:SIMPLE和 key: index_things_on_active_and_date。
SELECT *您所说的和 的EXPLAIN 计划SELECT id是相同的,将按访问的行数分隔。如何访问这些行?通过index_things_on_active_and_date索引。EXPLAIN 中的SIMPLE表示它是扫描。在这两种情况下,它都是基于active=1和 的索引扫描date < '2015-07-11 00:00:00'
索引扫描是如何发生的?
active和date,因此范围扫描将从两列进行。WHERE条款。您正在检索owner_id并status检查这些值。这需要您访问整行。
SELECT *意味着您将整行作为结果集的一部分SELECT id意味着您将 id 作为结果集的一部分这通向哪里?
id值结果会花费更长的时间来构建您阅读的整行。您自己进行了实证测试并发现了以下内容:
< 200 rows->SELECT id更快> 200 rows->SELECT *更快= 200 rows->SELECT id和SELECT *大致相同关于 InnoDB 还有一些你需要了解的事情
这告诉您索引index_things_on_active_and_date实际上有三列: 1) active, 2) date, 3) id。
您可能会说:为什么SELECT *跑步更好SELECT id?(这是最初的问题)这又回到了我所说的:WHERE 子句导致查询优化器检查非索引列status和owner_id. 您正在创建额外的工作,检查索引条目以及索引行中的某些内容。
如果你创建这个索引
ALTER TABLE things
ADD INDEX index_everything_and_kitchen_sink
(active,date,owner_id,status)
;
Run Code Online (Sandbox Code Playgroud)
SELECT id并运行这两个查询,那么无论您访问多少行,您都会看到优势。为什么 ?因为WHERE 子句中的所有列仅从索引中检查。这种类型的索引称为覆盖索引。
以下是一些关于覆盖索引的好链接
我在一些答案中提到了这些链接:
Feb 10, 2012 意外的极长查询时间(使用嵌套 WHEN-IN 约 5 分钟)Oct 17, 2012:合并索引中的列Jan 11, 2013: MySQL: 使用MYISAM还是INNODB引擎?(附上剧情转折)| 归档时间: |
|
| 查看次数: |
191 次 |
| 最近记录: |