Mysql 中的 Index Scope 是如何工作的?
Posted
技术标签:
【中文标题】Mysql 中的 Index Scope 是如何工作的?【英文标题】:How does Index Scope work in Mysql? 【发布时间】:2016-01-06 14:41:10 【问题描述】:在 mysql 手册中有一个页面 index hinting 提到您可以为查询的特定部分指定索引提示。
您可以通过在提示中添加
FOR
子句来指定索引提示的范围。这为优化器为查询处理的各个阶段选择执行计划提供了更细粒度的控制。要仅影响 MySQL 决定如何在表中查找行以及如何处理连接时使用的索引,请使用FOR JOIN
。要影响对行进行排序或分组的索引使用,请使用FOR ORDER BY
或FOR GROUP BY
。
但是,关于它是如何工作的或它在 MySQL 优化器中实际作用的信息很少甚至没有。在实践中,它在实际改进任何东西方面似乎都可以忽略不计。
这是一个测试查询,以及关于该查询的解释:
SELECT
`property`.`primary_id` AS `id`
FROM `California` `property`
USE INDEX FOR JOIN (`Zipcode Bedrooms`)
USE INDEX FOR ORDER BY (`Zipcode Bathrooms`)
INNER JOIN `application_zipcodes` `az`
ON `az`.`application_id` = '18'
AND `az`.`zipcode` = `property`.`zipcode`
WHERE `property`.`city` = 'San Jose'
AND `property.`zipcode` = '95133'
AND `property`.property_type` = 'Residential'
AND `property`.`style` = 'Condominium'
AND `property`.`bedrooms` = '3'
ORDER BY `property`.`bathrooms` ASC
LIMIT 15
;
解释:
EXPLAIN SELECT `property`.`primary_id` AS `id` FROM `California` `property` USE INDEX FOR JOIN (`Zipcode Bedrooms`) USE INDEX FOR ORDER BY (`Zipcode Bathrooms`) INNER JOIN `application_zipcodes` `az` ON `az`.`application_id` = '18' AND `az`.`zipcode` = `property`.`zipcode` WHERE `property`.`city` = 'San Jose' AND `property.`zipcode` = '95133' AND `property`.property_type` = 'Residential' AND `property`.`style` = 'Condominium' AND `property`.`bedrooms` = '3' ORDER BY `property`.`bathrooms` ASC LIMIT 15\g
+------+-------------+----------+--------+---------------+---------+---------+------------------------------------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+--------+---------------+---------+---------+------------------------------------+------+----------------------------------------------------+
| 1 | SIMPLE | Property | ref | Zip Bed | Zip Bed | 17 | const,const | 2364 | Using index condition; Using where; Using filesort |
| 1 | SIMPLE | az | eq_ref | PRIMARY | PRIMARY | 7 | const,Property.zipcode | 1 | Using where; Using index |
+------+-------------+----------+--------+---------------+---------+---------+------------------------------------+------+----------------------------------------------------+
2 rows in set (0.01 sec)
总而言之,我基本上想知道如何使用索引范围,因为当我添加或删除行 USE INDEX FOR ORDER BY (Zipcode Bathrooms)
时,这似乎没有任何作用。
【问题讨论】:
【参考方案1】:我还没有弄清楚如何使用多个提示。 MySQL 几乎不会在每个SELECT
中使用一个以上的索引。我知道的唯一例外是“索引合并”,这与您的示例无关。
优化器通常专注于为WHERE
子句寻找一个好的索引。如果它完全覆盖了WHERE
,没有任何“范围”,那么它会检查是否有GROUP BY
和ORDER BY
字段以正确的顺序使用。如果它可以处理所有WHERE, GROUP BY, and ORDER BY
,那么它实际上可以优化LIMIT
(但不是OFFSET
)。
如果优化器不能消耗所有WHERE
,它可能会到达ORDER BY
,希望避免ORDER BY
否则需要的“文件排序”。
这些都不允许为不同的子句使用不同的索引。一个提示可能会鼓励优先使用上述情况之一(上图);我不知道。
邮政编码不要使用 utf8;它使事情变得不必要(每个字符 3 个字节)。一般来说,缩小表的大小会有助于提高一些性能。或者,如果你有一个庞大的数据集,它可能对性能有很大帮助。 (避免 I/O 非常重要。)
Bathrooms
不是很挑剔;即使有可能,也没有什么收获。
az.application_id
是查询中的大扳手;这是什么?
【讨论】:
本质上,这是一种在我拥有的邮政编码列表之间建立一对多关系的方法。 You actually commented on that issue that I was having and this result appears to be the fastest outcome. 如果使用正确的索引,问题中的这个查询实际上非常快,但是优化器会尝试选择错误的索引,从而导致文件排序。我也不能删除任何一个索引,因为它们都是排序所必需的。 无法再次编辑我的上一条评论。你说,Bathrooms is not very selective; there is not much to gain even if it would be possible.
虽然这在 where 语句的情况下是正确的,但它有很多行,所以使用它作为 order by 的索引比在Bedrooms
上使用索引要快得多。还想指出,我也尝试使用巨大的 Union All 作为邮政编码,它确实很快,但这需要由我以外的其他开发人员进行管理,所以我认为与当前相比,复杂的抽象可以稍微提高速度是不值得。以上是关于Mysql 中的 Index Scope 是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章
相当于mySQL中的SQL Server函数SCOPE_IDENTITY()?