有没有办法提示 mysql 使用 Using index for group-by
Posted
技术标签:
【中文标题】有没有办法提示 mysql 使用 Using index for group-by【英文标题】:Is there a way to hint mysql to use Using index for group-by 【发布时间】:2013-12-17 20:17:49 【问题描述】:我正忙于探索 GROUP BY 优化。在经典的“每个部门的最高工资”查询中。突然奇怪的结果。下面的转储从我的控制台直接。这两个解释之间没有发出命令。只过了一段时间。
mysql> explain select name, t1.dep_id, salary
from emploee t1
JOIN ( select dep_id, max(salary) msal
from emploee
group by dep_id
) t2
ON t1.salary=t2.msal and t1.dep_id = t2.dep_id
order by salary desc;
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 4 | Using temporary; Using filesort |
| 1 | PRIMARY | t1 | ref | dep_id | dep_id | 8 | t2.dep_id,t2.msal | 1 | |
| 2 | DERIVED | emploee | index | NULL | dep_id | 8 | NULL | 84 | Using index |
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+
3 rows in set (0.00 sec)
mysql> explain select name, t1.dep_id, salary
from emploee t1
JOIN ( select dep_id, max(salary) msal
from emploee
group by dep_id
) t2
ON t1.salary=t2.msal and t1.dep_id = t2.dep_id
order by salary desc;
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 4 | Using temporary; Using filesort |
| 1 | PRIMARY | t1 | ref | dep_id | dep_id | 8 | t2.dep_id,t2.msal | 3 | |
| 2 | DERIVED | emploee | range | NULL | dep_id | 4 | NULL | 9 | Using index for group-by |
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+
3 rows in set (0.00 sec)
您可能会注意到,它在第二次运行时检查的行数减少了十倍。我认为这是因为一些内部计数器已更改。但我不想依赖这些计数器。那么 - 有没有办法提示 mysql 仅使用“使用索引进行分组”行为?
或者 - 如果我的推测是错误的 - 是否有任何其他解释该行为以及如何解决它?
CREATE TABLE `emploee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`dep_id` int(11) NOT NULL,
`salary` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `dep_id` (`dep_id`,`salary`)
) ENGINE=InnoDB AUTO_INCREMENT=85 DEFAULT CHARSET=latin1 |
+-----------+
| version() |
+-----------+
| 5.5.19 |
+-----------+
【问题讨论】:
【参考方案1】:嗯,显示索引的基数可能会有所帮助,但请记住:range
通常慢然后index
es 在那里。
因为它认为它可以匹配第一个索引中的完整索引,所以它使用完整索引。在第二个中,它删除索引并进入一个范围,但猜测满足 larger 范围的总行数大大低于 smaller 完整索引,因为所有基数发生了变化。比较一下:为什么 "AA" 匹配 84 行,但 "A[any character]" 只匹配 9 (注意它在第一个中使用 8 个字节的键,在第二个中使用 4 个字节)?第二个实际上不会读取更少的行,EXPLAIN
只是在更新它的索引元数据后以不同的方式猜测行数。 EXPLAIN
也不是不告诉你一个查询会做什么,而是它可能会做什么。
更新基数可以或will occur when:
表的每个索引中的基数(不同键值的数量)是在打开表时计算的,在 SHOW TABLE STATUS 和 ANALYZE TABLE 以及其他情况下(例如当表更改太多时)。请注意,如果 auto-rehash 设置设置为 on(默认值),则在 mysql 客户端启动时会打开所有表并重新估计统计信息。
因此,假设“在任何时候”由于“变化太多”,是的,连接mysql
客户端可以改变选择服务器索引的行为。另外:在超时后失去连接后重新连接 mysql 客户端算作使用自动重新哈希 AFAIK 连接。如果您想帮助 mysql 找到正确的方法,请偶尔运行ANALYZE TABLE
,尤其是在大量更新之后。如果您认为它猜测的基数通常是错误的,您可以 alter the number of pages 它读取以猜测一些统计信息,但请记住,数字越大意味着该基数的运行更新时间越长,并且您不希望经常发生的事情当有很多操作的表上的“数据变化很大”时。
TL;DR:它以不同的方式猜测行,但如果数据允许,您实际上更喜欢第一种行为。
添加:
在这个previously linked page 上,我们可能也可以找到为什么特别是dep_id
可能有这个问题:
像 1 或 2 这样的小值会导致对基数的估计非常不准确
我可以想象不同的dep_id
的数量通常很小,而且我确实观察到非唯一索引上的“弹跳”基数与我自己的行数相比范围相当小数据库。它很容易猜出数百个中的 1-10 个范围,然后下一次再次向下猜测,这只是基于它选择的特定示例页面和一些试图推断的算法。
【讨论】:
以上是关于有没有办法提示 mysql 使用 Using index for group-by的主要内容,如果未能解决你的问题,请参考以下文章
Mysql登录出错 user root@localhost(using password:NO)
phpMyAdmin提示“Access denied for user 'root'@'localhost' (using password: NO)”的解决办法(代码
有没有办法在 Redshift Spectrum 中使用“IN”条件检查多个列?
MySQL5.7出现Your password has expired. To log in you must change it using a client that supports expir
pip安装出现Fatal error in launcher: Unable to create process using '"'的解决办法
iOS之报错“Cannot create __weak reference in file using manual reference counting”解决办法