使用索引进行Mysql查询优化

时间:2011-07-14 16:26:42

标签: mysql performance indexing

我的db模式由以下两个表组成:

CREATE TABLE `categories` (
  `id` bigint(20) NOT NULL auto_increment,
  `title` varchar(128) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `articles` (
  `id` bigint(20) NOT NULL auto_increment,
  `title` varchar(512) NOT NULL,
  `body` longtext,
  `state` varchar(7) NOT NULL,
  `type` varchar(6) NOT NULL,
  `category` bigint(20) default NULL,
  `publishedAt` datetime default NULL,
  PRIMARY KEY  (`id`),
  KEY `FK_category_to_article_category` (`category`),
  CONSTRAINT `FK_category_to_article_category` FOREIGN KEY (`category`) REFERENCES `categories` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

对于文章表,state列的值为“PUBLISHED”或“UNPUBLISHED”,type列的值为“NEWS”,“GOSSIP”和“OPINION”。

我的应用程序执行了很多这样的查询:

select * from articles where state="PUBLISHED" and type in ("NEWS","GOSSIP") 
and category in (4) and publishedAt<=now() order by publishedAt desc;

我有~10K文章,我试图确定上面的查询是否在类别上使用默认外键更好,或者我应该使用多列索引。

没有索引(使用“explain extended”):

+----+-------------+-------+------+---------------------------------+---------------------------------+---------+-------+------+-----------------------------+
| id | select_type | table | type | possible_keys                   | key                             | key_len | ref   | rows | Extra                       |
+----+-------------+-------+------+---------------------------------+---------------------------------+---------+-------+------+-----------------------------+
|  1 | SIMPLE      | this_ | ref  | FK_category_to_article_category | FK_category_to_article_category | 9       | const |  630 | Using where; Using filesort |
+----+-------------+-------+------+---------------------------------+---------------------------------+---------+-------+------+-----------------------------+

如果我创建多列索引并再次解释(强制使用特定索引):

create index I_s_t_c_p on articles (state, type, category, publishedAt);


+----+-------------+-------+-------+---------------+-----------+---------+------+------+------------------------------------------+
| id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra                                    |
+----+-------------+-------+-------+---------------+-----------+---------+------+------+------------------------------------------+
|  1 | SIMPLE      | this_ | range | I_s_t_c_p     | I_s_t_c_p | 61      | NULL | 1216 | Using where; Using index; Using filesort |
+----+-------------+-------+-------+---------------+-----------+---------+------+------+------------------------------------------+

查询实际返回的行数是630.在我看来,由于使用了所有索引列,因此多列索引应该比FK执行得更好,但是在使用索引时检查了~1200行的事实困惑我。我知道这些数字只是估计,但两个键之间的差异非常大;使用组合索引,我们检查了双倍的行数。

所以我的问题如下:

  1. 为什么用多列索引检查了这么多行?
  2. 由于使用FK我们有一个连接类型“ref”并且使用组合索引我们有一个连接类型“range”,这是否意味着使用FK的查询比另一个更好/更快?
  3. 我应该将检查的行数估算用作判断索引是否良好/最佳的标准吗?
  4. 在这个用例中,多列索引是否比FK更好?我应该在什么基础上做出决定?
  5. 其他一些信息:

    • 在不强制查询索引的情况下,优化器选择了FK。当我在文章上执行analyze table时,选择了多列索引。
    • 我正在使用MySql 5.0.15
    • 索引信息
    
    +----------+------------+---------------------------------+--------------+-------------+-------------+------------+
    | Table    | Non_unique | Key_name                        | Seq_in_index | Column_name | Cardinality | Index_type |
    +----------+------------+---------------------------------+--------------+-------------+-------------+------------+
    | articles |          0 | PRIMARY                         |            1 | id          |       12561 | BTREE      |
    | articles |          1 | FK_category_to_article_category |            1 | category    |          37 | BTREE      |
    | articles |          1 | I_s_t_c_p                       |            1 | state       |           8 | BTREE      |
    | articles |          1 | I_s_t_c_p                       |            2 | type        |          32 | BTREE      |
    | articles |          1 | I_s_t_c_p                       |            3 | category    |         163 | BTREE      |
    | articles |          1 | I_s_t_c_p                       |            4 | publishedAt |       12561 | BTREE      |
    +----------+------------+---------------------------------+--------------+-------------+-------------+------------+
    

    提前致谢。

1 个答案:

答案 0 :(得分:2)

正如您所看到的,publishedAt上的索引具有与PK相同的基数。这并没有真正帮助。我会尝试按照(category,type,state)的顺序创建一个包含列的复合索引。这样,索引的第一部分就是最具选择性的。