MySQL优化orderby日期查询

时间:2010-11-12 23:33:46

标签: mysql

我尽力解决以下两个简单查询,但对于每10行结果集,它会扫描整个表或至少10K行。目前书籍表中有20000行。

ALTER TABLE books ADD INDEX search_INX (`book_status`, `is_reviewed`,`has_image`,`published_date`)

mysql> EXPLAIN SELECT book_id FROM books ORDER BY published_date DESC LIMIT 10;
+----+-------------+-------+-------+---------------+------------+---------+------+-------+-----------------------------+
| id | se ref  |lect_type | table | type  | possible_keys | key        | key_len | rows  | Extra                       |
+----+-------------+-------+-------+---------------+------------+---------+------+-------+-----------------------------+
|  1 | SIMPLE      | books | index | NULL          | search_INX | 11      | NULL | 20431 | Using index; Using filesort | 
+----+-------------+-------+-------+---------------+------------+---------+------+-------+-----------------------------+

mysql> EXPLAIN SELECT book_id FROM books WHERE book_status='available' AND is_reviewed=true AND has_image=true ORDER BY published_date DESC LIMIT 10;
+----+-------------+-------+------+---------------+------------+---------+-------------------+-------+--------------------------+
| id | select_type | table | type  ref               || possible_keys | key        | key_len | rows  | Extra                    |
+----+-------------+-------+------+---------------+------------+---------+-------------------+-------+--------------------------+
|  1 | SIMPLE      | books | ref  | search_INX    | search_INX | 3       | const,const,const | 10215 | Using where; Using index | 
+----+-------------+-------+------+---------------+------------+---------+-------------------+-------+--------------------------+

mysql> EXPLAIN SELECT book_id FROM books WHERE book_status='available' AND is_reviewed=true AND has_image=true ORDER BY published_date DESC LIMIT 10\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: books
         type: ref
possible_keys: search_INX
          key: search_INX
      key_len: 3
          ref: const,const,const
         rows: 10215
        Extra: Using where; Using index
1 row in set (0.00 sec)

Create Table: CREATE TABLE `books` (
  `book_id` int(10) unsigned NOT NULL auto_increment,
  `has_image` bit(1) NOT NULL default '',
  `is_reviewed` bit(1) NOT NULL default '\0',
  `book_status` enum('available','out of stock','printing') NOT NULL default 'available',
  `published_date` datetime NOT NULL,
  PRIMARY KEY  (`book_id`),
  KEY `search_INX` (`is_reviewed`,`has_image`,`book_status`,`published_date`)
) ENGINE=InnoDB AUTO_INCREMENT=162605 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

有没有人知道如何解决这个问题?

6 个答案:

答案 0 :(得分:2)

基数:

KEY `search_INX` (`is_reviewed`,`has_image`,`book_status`,`published_date`)

......很穷。如果你将published_date放在前面,它会加快你的查询速度。此外,为什么要索引is_reviewed& has_image?布尔列甚至不能在SQL Server之类的索引中,因为没有必要这样做(再次,基数)。重新安排你的钥匙,或在我提到的栏目上放一个唯一的钥匙。

答案 1 :(得分:1)

快速浏览一下,问题似乎是你缺少在published_date上的索引。 Order by正在使用此列。添加此索引,看看会发生什么。

答案 2 :(得分:1)

此外,rows列中的mysql不会显示受影响的行数,但会显示近似可能受影响的行数,不包括 LIMIT条款。

答案 3 :(得分:0)

我不是索引方面的专家,但您是否可以仅在published_date上创建索引以及在所有四个字段上创建的索引?

ALTER TABLE books DROP INDEX `search_INX`;
ALTER TABLE books ADD INDEX `published_INX` (`published_date`);

答案 4 :(得分:0)

如果您使用FORCE INDEX命令,这有帮助吗?

答案 5 :(得分:0)

@Zerkms @jason我只想到另一种解决方法。

这是非正统的,但会起作用。如果您的主键是(publish_date,book_id)并使用DESC排序,您将很容易获得最后10个结果。查询引擎将扫描表,应用where子句,直到找到10个结果,然后退出。

它会很棒。如果您需要通过book_id专门查询,只需在book_id上添加另一个索引。

这有道理的原因是DB会自然地按日期存储书籍(InnoDB使用聚簇索引),这正是您要查询的内容。