Mic*_*ssa 4 mysql sql explain sql-execution-plan
在MySQL的5.7文档状态:
该
filtered列指示将由表条件过滤的表行的估计百分比。也就是说,rows显示估计的检查行数并rows × filtered / 100显示将与先前表连接的行数。
为了更好地理解这一点,我在使用MySQL Sakila 示例数据库的查询中进行了尝试。有问题的表具有以下结构:
mysql> SHOW CREATE TABLE film \G
*************************** 1. row ***************************
Table: film
Create Table: CREATE TABLE `film` (
`film_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`description` text,
`release_year` year(4) DEFAULT NULL,
`language_id` tinyint(3) unsigned NOT NULL,
`original_language_id` tinyint(3) unsigned DEFAULT NULL,
`rental_duration` tinyint(3) unsigned NOT NULL DEFAULT '3',
`rental_rate` decimal(4,2) NOT NULL DEFAULT '4.99',
`length` smallint(5) unsigned DEFAULT NULL,
`replacement_cost` decimal(5,2) NOT NULL DEFAULT '19.99',
`rating` enum('G','PG','PG-13','R','NC-17') DEFAULT 'G',
`special_features` set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') DEFAULT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`film_id`),
KEY `idx_title` (`title`),
KEY `idx_fk_language_id` (`language_id`),
KEY `idx_fk_original_language_id` (`original_language_id`),
CONSTRAINT `fk_film_language` FOREIGN KEY (`language_id`) REFERENCES `language` (`language_id`) ON UPDATE CASCADE,
CONSTRAINT `fk_film_language_original` FOREIGN KEY (`original_language_id`) REFERENCES `language` (`language_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8
Run Code Online (Sandbox Code Playgroud)
这是EXPLAIN查询的计划:
mysql> EXPLAIN SELECT * FROM film WHERE release_year=2006 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: film
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1000
filtered: 10.00
Extra: Using where
Run Code Online (Sandbox Code Playgroud)
此表的示例数据集共有 1,000 行,并且所有行都release_year设置为 2006。使用 MySQL 文档中的公式:
rows x filtered / 100 = "将与先前表连接的行数
所以,
1,000 x 10 / 100 = 100 = "100 行将与之前的表连接"
嗯?什么“上一张桌子”?这里没有任何JOIN进展。
文档中引用的第一部分怎么样?“将由表条件过滤的表行的估计百分比。” 好吧,表条件是release_year = 2006,并且所有记录都具有该值,所以不filtered应该是0.00or 100.00(取决于它们所说的“过滤”是什么意思)?
也许它的行为很奇怪,因为没有索引release_year?所以我创建了一个:
mysql> CREATE INDEX test ON film(release_year);
Run Code Online (Sandbox Code Playgroud)
该filtered列现在显示100.00。那么,它不应该0.00在我添加索引之前显示吗?嗯。如果我让一半的表release_year是 2006 年,另一半不是怎么办?
mysql> UPDATE film SET release_year=2017 ORDER BY RAND() LIMIT 500;
Query OK, 500 rows affected (0.03 sec)
Rows matched: 500 Changed: 500 Warnings: 0
Run Code Online (Sandbox Code Playgroud)
现在EXPLAIN看起来像这样:
mysql> EXPLAIN SELECT * FROM film WHERE release_year=2006 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: film
partitions: NULL
type: ref
possible_keys: test
key: test
key_len: 2
ref: const
rows: 500
filtered: 100.00
Extra: Using index condition
Run Code Online (Sandbox Code Playgroud)
而且,因为我决定进一步混淆自己:
mysql> EXPLAIN SELECT * FROM film WHERE release_year!=2006 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: film
partitions: NULL
type: ALL
possible_keys: test
key: NULL
key_len: NULL
ref: NULL
rows: 1000
filtered: 50.10
Extra: Using where
Run Code Online (Sandbox Code Playgroud)
那么,估计 501 行将被表条件过滤并“与以前的表连接”?
我简直不明白。
我意识到这是一个“估计”,但这个估计基于什么?如果存在的索引将估计值移动到100.00,那么它的缺失不应该是0.00,不是10.00吗?有了这样有什么50.10结果在最后一次查询?
filtered在确定查询是否可以进一步优化,或者如何进一步优化它,或者它通常只是可以忽略的“噪音”时,它是否有用?
…将与先前表连接的行数…
在没有任何连接的情况下,我相信这可以理解为行数
更新- 至少现在文档说“下表”但重点仍然存在,谢谢@WilsonHauck
依次拿你的每个例子
1000 行,全部来自 2006 年,没有索引……
EXPLAIN SELECT * FROM film WHERE release_year = 2006
key: NULL
rows: 1000
filtered: 10.00
Extra: Using where
Run Code Online (Sandbox Code Playgroud)
这里引擎期望访问 1000 行,并期望返回其中的 10% 左右
由于查询未使用索引,因此预测每一行都将被检查是有意义的,但不幸的是过滤后的估计是不准确的。我不知道引擎是如何做出这个预测的,但因为它不知道所有的行都是 2006 年的(直到它检查它们......这不是世界上最疯狂的事情
也许在没有更多信息的情况下,引擎期望任何简单的=条件将结果集减少到可用行的 10%
1000 行,2006 年的一半,带有索引…
EXPLAIN SELECT * FROM film WHERE release_year = 2006
key: test
rows: 500
filtered: 100.00
Extra: Using index condition
Run Code Online (Sandbox Code Playgroud)
这里引擎期望访问 500 行并期望返回所有行
现在查询使用的是新索引,引擎可以做出更准确的预测。它可以很快看到 500 行与条件匹配,并且只需要访问这些行来满足查询
EXPLAIN SELECT * FROM film WHERE release_year != 2006
key: NULL
rows: 1000
filtered: 50.10
Extra: Using where
Run Code Online (Sandbox Code Playgroud)
这里引擎期望访问 1000 行并返回其中的 50.10%
引擎选择不使用索引,可能!=操作不像=本例那样简单,因此预测每一行都将被访问是有意义的
然而,引擎已经对将返回多少这些访问过的行进行了相当准确的预测。我不知道 .10% 来自哪里,但也许引擎已经使用索引或先前查询的结果来识别大约 50% 的行将匹配条件
这有点像黑暗艺术,但该filtered值确实为您提供了一些相当有用的信息,以及对引擎做出某些决定的原因的一些见解
如果行数很高并且过滤的行估计值很低(并且准确),这可能是一个很好的迹象,表明精心应用的索引可以加快查询速度
| 归档时间: |
|
| 查看次数: |
5724 次 |
| 最近记录: |