2013-12-17 166 views
0

我忙于探索GROUP BY优化。在经典的“最高薪水每出发”查询。突然奇怪的结果。下面的转储从我的控制台去。这两个解释之间没有发布命令。只过了一段时间。有没有办法暗示mysql使用使用索引的组 -

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使用“仅使用index for group”行为?

或者 - 如果我的猜测是错误的 - 是否有任何其他解释的行为和如何解决它?

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 | 
+-----------+ 

回答

3

嗯,显示指数的基数可能会有帮助,但要记住:range的通常是然后index ES那里。

因为它认为它可以匹配第一个完整的索引,它使用完整的索引。在第二种情况下,它会降低索引并达到一个范围,但会猜测总行数满足较大的范围大大低于较小的全索引,因为所有基数都已更改。比较一下:为什么“AA”匹配84行,但“A [任意字符]”只匹配9(注意它使用第一个字节的8个字节,第二个字节使用4个字节)?第二个实际上不会读取更少的行,EXPLAIN只是在更新索引的元数据后猜测行数。也不是那EXPLAIN确实不是告诉你什么查询做什么,但可能会做什么。

更新基数可以或will occur when

在一个表中的每一个索引的基数(不同的密钥值的数量)是当一个表被打开时,在SHOW TABLE状况,分析表,并在计算出的其他情况(比如表格变化太大时)。请注意,如果自动重新刷新设置设置为开启(默认),则mysql客户端启动时将打开所有表并重新估计统计信息。

因此,假设“在任何时候”,由于“变化太大了”,是的,与mysql客户连接可以改变在选择服务器的索引行为。另外:在超时之后失去连接后重新连接mysql客户端连接自动rehash AFAIK。如果你想让mysql帮忙找到正确的方法,那么偶尔运行ANALYZE TABLE,特别是在大量更新之后。如果你认为它猜测的基数常常是错误的,你可以用alter the number of pages来猜测一些统计数据,但记住一个更高的数字意味着该基数的更长时间的运行更新,而当你想要“数据在很多操作的桌子上变成了很多'。

TL; DR:它猜测行的方式不同,但如果数据可行,您实际上更喜欢第一种行为。

添加: 在此previously linked page,我们可以大概也觉得为什么特别dep_id可能有这样的问题:

像1或2小值会导致基数

的非常不准确的估计

我可以想象不同的dep_id的数量通常很小,而且我确实观察到非“非弹性”基数 - 与我自己的数据库中的行数相比,具有相当小范围的唯一索引。它很容易猜出数百个1-10的范围,然后再下一次,只是基于它选取的具体样本页面&某些算法试图推断。

相关问题