2009-07-17 82 views
7

我有一个基于3列的复合索引,其中两个约束在我的查询中,第三个约束在子句中,但mysql不使用索引进行排序。优化我的mysql查询以使用索引进行排序

 
explain select * from videos where public_private='public' and approved='yes' order by number_of_views desc; 

+----+-------------+--------+------+--------------------------------+------+---------+------+---------+-----------------------------+ 
| id | select_type | table | type | possible_keys     | key | key_len | ref | rows | Extra  | 
+----+-------------+--------+------+--------------------------------+------+---------+------+---------+-----------------------------+ 
| 1 | SIMPLE  | videos | ALL | approved,approved_3,approved_2 | NULL | NULL | NULL | 1476818 | Using where; Using filesort | 
+----+-------------+--------+------+--------------------------------+------+---------+------+---------+-----------------------------+ 

表结构如下:

CREATE TABLE `videos` (
    `indexer` int(9) NOT NULL auto_increment, 
    `user_id` int(9) default NULL, 
    `public_private` varchar(24) default NULL, 
    `approved` varchar(24) default NULL, 
    `number_of_views` int(9) default NULL, 
    PRIMARY KEY (`indexer`), 
    KEY `approved` (`approved`,`user_id`), 
    KEY `approved_3` (`approved`,`public_private`,`indexer`), 
    KEY `approved_2` (`approved`,`public_private`,`number_of_views`), 
) ENGINE=MyISAM AUTO_INCREMENT=1969091 DEFAULT CHARSET=utf8 | 

我应该怎么做来强制MySQL使用索引排序的结果?

回答

13

我相信你有查询可能匹配的有很大比例是特别关键数据在表中。在这种情况下,MySQL优化器经常选择进行表扫描并完全忽略索引,因为它实际上比通过额外读取整个索引并使用它来挑选数据的麻烦要快。所以在这种情况下,我猜测public_private='yes' and approved='yes'与您的表的很大一部分相匹配。因此,如果MySQL因此而跳过索引,那么它也不可用于排序。

如果你真的希望它使用一个索引,那么解决办法是使用FORCE INDEX

select * from videos FORCE INDEX (approved_2) where public_private='public' and approved='yes' order by number_of_views desc; 

不过,我会运行一些测试,以确保什么你得到实际上比更快MySQL优化器选择做什么。显然,优化程序does have some issues可以为订购做出选择,所以您可以肯定地给出这一步,看看您是否获得了改进的性能。

+0

FORCE INDEX解决了问题。现在查询执行速度快得多,而且您对查询匹配大部分数据库是正确的。 – 2009-07-18 11:02:47

+0

好东西,很高兴它的工作。 – zombat 2009-07-18 16:36:20

-2

订单在组合键中很重要。我忘记规则,但尝试以不同的顺序。

-2

number_of_views列中添加单独的索引,然后查看它是否有效。

如果键是3列的组合,它将使用,只有当它使用所有3执行操作

+0

编号正确的是:如果一个键是3列的组合,当它使用第一列或前两列或所有三列的组合时,将使用该特定键 – 2017-01-12 09:14:54

1

该命令在组合键中很重要。如果你想通过刚才number_of_views使用approved_2键,更改排序:

KEY `approved_2` (`approved`,`public_private`,`number_of_views`) 

到:

KEY `approved_2` (`number_of_views`,`approved`,`public_private`) 

左到右MySQL的工作组合键。在上面的例子中,重点用number_of_viewsapproved申报,并public_private含蓄上创建索引:

  • number_of_views
  • number_of_viewsapproved
  • number_of_viewsapprovedpublic_private
+0

这个解决方案只会剥夺MySQL的可能性来过滤前两个字段并对第三个字段进行排序。 – Quassnoi 2009-07-17 18:20:41

0

这应该工作:

`select * from videos where approved='yes' and public_private='public' order by number_of_views desc;` 

如果没有,只需在number_of_views上创建一个单独的索引。

这必须工作。

(MySQL的如下左向右的顺序基本上是这样。所以你对approved指数,public_privatenumber_of_views不会,如果不在这个序列中使用工作。也就是说,你可以使用从左边三个左,2个或最左边的1 。但是如果你不使用最左边的那个,这是不行的,这就是主意。)

使用一个单独的索引会自动排序number_of_views,这可能有助于order by - 我确信这一点。