我的mysql索引没有任何效果

时间:2009-07-28 13:35:57

标签: sql mysql

我有以下查询:

mysql> explain SELECT Exhibition.venue_id, Exhibition.name, Exhibition.slug, Venue.name, Venue.slug, Venue.location_id, Venue.id, Exhibition.id FROM exhibitions AS Exhibition LEFT JOIN venues AS Venue ON (Exhibition.venue_id = Venue.id) LEFT JOIN temperatures AS Temperature ON (Temperature.ref = Exhibition.id) WHERE Exhibition.active = '1' AND Exhibition.ends <= CURDATE() ORDER BY Temperature.temperature DESC LIMIT 5;
+----+-------------+-------------+--------+---------------+---------+---------+--------------------------+------+----------------------------------------------+
| id | select_type | table       | type   | possible_keys | key     | key_len | ref                      | rows | Extra                                        |
+----+-------------+-------------+--------+---------------+---------+---------+--------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | Exhibition  | ALL    | NULL          | NULL    | NULL    | NULL                     | 1530 | Using where; Using temporary; Using filesort | 
|  1 | SIMPLE      | Venue       | eq_ref | PRIMARY       | PRIMARY | 108     | narb.Exhibition.venue_id |    1 |                                              | 
|  1 | SIMPLE      | Temperature | ALL    | NULL          | NULL    | NULL    | NULL                     | 2649 |                                              | 
+----+-------------+-------------+--------+---------------+---------+---------+--------------------------+------+----------------------------------------------+
3 rows in set (0.00 sec)

现在因为(Exhibition.venue_id,Exhibition.active,Exhibition.ends)和Temperature.ref上有一个索引,我希望第一个和最后一个连接能够使用索引。你可以看到它没有。

起初我虽然必须与计算日期有关,但即使没有日期过滤器,也不会使用索引。我尝试了几种不同的索引,但我发现了更多。我在这里缺少什么?

相关的表索引是:

ALTER TABLE exhibitions ADD INDEX(slug);
ALTER TABLE exhibitions ADD INDEX(venue_id, ends);

ALTER TABLE temperatures ADD INDEX(ref);

并且,根据要求,展览也会创建表格查询:

CREATE TABLE `exhibitions` (
  `id` char(36) NOT NULL,
  `clue` char(6) NOT NULL DEFAULT '',
  `venue_id` char(36) NOT NULL,
  `name` varchar(255) NOT NULL,
  `slug` varchar(255) NOT NULL,
  `description` text,
  `starts` date DEFAULT NULL,
  `ends` date DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  `user_id` char(36) NOT NULL,
  `featured` tinyint(1) NOT NULL DEFAULT '0',
  `permanent` tinyint(1) unsigned NOT NULL DEFAULT '0',
  `active` tinyint(1) unsigned NOT NULL DEFAULT '1',
  `cidn` varchar(255) DEFAULT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `slug` (`slug`),
  KEY `cidn` (`cidn`),
  KEY `venue_id` (`venue_id`,`ends`),
  KEY `venue_id2` (`venue_id`),
  FULLTEXT KEY `name` (`name`,`description`,`url`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

添加了统计信息:

mysql> SELECT  *
-> FROM    information_schema.statistics
-> WHERE   UPPER(table_name) = UPPER('temperatures')
->         AND UPPER(column_name) = UPPER('ref');
+---------------+--------------+--------------+------------+--------------+------------+--------------+-------------+-----------+-------------+----------+--------+----------+------------+---------+
| TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME   | NON_UNIQUE | INDEX_SCHEMA | INDEX_NAME | SEQ_IN_INDEX | COLUMN_NAME | COLLATION | CARDINALITY | SUB_PART | PACKED | NULLABLE | INDEX_TYPE | COMMENT |
+---------------+--------------+--------------+------------+--------------+------------+--------------+-------------+-----------+-------------+----------+--------+----------+------------+---------+
| NULL          | narb         | temperatures |          0 | narb         | unique_ref |            1 | ref         | A         |        2655 |     NULL | NULL   |          | BTREE      |         | 
| NULL          | narb         | temperatures |          1 | narb         | ref        |            1 | ref         | A         |        2655 |     NULL | NULL   |          | BTREE      |         | 
+---------------+--------------+--------------+------------+--------------+------------+--------------+-------------+-----------+-------------+----------+--------+----------+------------+---------+
2 rows in set (0.02 sec)

更新了Quassnoi sugesstion的结果:

mysql> EXPLAIN
-> SELECT  Exhibition.venue_id, Exhibition.name, Exhibition.slug,
->         Venue.name, Venue.slug, Venue.location_id,
->         Venue.id, Exhibition.id
-> FROM    exhibitions AS Exhibition
-> LEFT JOIN
->         venues AS Venue
-> ON      Venue.id = Exhibition.venue_id
-> LEFT JOIN
->         temperatures AS Temperature FORCE INDEX (unique_ref)
-> ON      Temperature.ref = Exhibition.id
-> WHERE   Exhibition.active = '1'
->         AND Exhibition.ends <= CURDATE()
-> ORDER BY
->         Temperature.temperature DESC
-> LIMIT 5;
+----+-------------+-------------+--------+---------------+---------+---------+--------------------------+------+----------------------------------------------+
| id | select_type | table       | type   | possible_keys | key     | key_len | ref                      | rows | Extra                                        |
+----+-------------+-------------+--------+---------------+---------+---------+--------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | Exhibition  | ALL    | NULL          | NULL    | NULL    | NULL                     | 1536 | Using where; Using temporary; Using filesort | 
|  1 | SIMPLE      | Venue       | eq_ref | PRIMARY       | PRIMARY | 108     | narb.Exhibition.venue_id |    1 |                                              | 
|  1 | SIMPLE      | Temperature | ALL    | NULL          | NULL    | NULL    | NULL                     | 2662 |                                              | 
+----+-------------+-------------+--------+---------------+---------+---------+--------------------------+------+----------------------------------------------+
3 rows in set (0.00 sec)

为温度添加了创建表:

CREATE TABLE `temperatures` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `ref` char(36) NOT NULL,
  `views` int(10) unsigned NOT NULL,
  `ratings` int(10) unsigned NOT NULL,
  `comments` int(10) unsigned NOT NULL,
  `bookmarks` int(10) unsigned NOT NULL,
  `tags` int(10) unsigned NOT NULL,
  `collected` int(10) unsigned NOT NULL default '0',
  `trips` int(10) unsigned NOT NULL,
  `fans` int(10) unsigned NOT NULL,
  `temperature` int(10) NOT NULL default '1000',
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `unique_ref` (`ref`),
  KEY `ref` (`ref`)
) ENGINE=MyISAM AUTO_INCREMENT=2743 DEFAULT CHARSET=latin1;

2 个答案:

答案 0 :(得分:2)

请您发布此查询的结果:

SELECT  *
FROM    information_schema.statistics
WHERE   UPPER(table_name) = UPPER('temperatures')
        AND UPPER(column_name) = UPPER('ref')

更新3:

您的exhibition表定义为CHARACTER SET UTF8,而temperatures定义为CHARACTER SET LATIN1

由于UTF8无法隐式转换为LATIN1,因此会向COLLATE UTF8添加隐式Temperature.ref,使其无法访问且索引无法使用。

您需要重写您的查询:

SELECT  Exhibition.venue_id, Exhibition.name, Exhibition.slug,
        Venue.name, Venue.slug, Venue.location_id,
        Venue.id, Exhibition.id
FROM    exhibitions AS Exhibition
LEFT JOIN
        venues AS Venue
ON      Venue.id = Exhibition.venue_id
LEFT JOIN
        temperatures AS Temperature FORCE INDEX (unique_ref)
ON      Temperature.ref = CAST(Exhibition.id AS CHAR CHARACTER SET latin1)
WHERE   Exhibition.active = '1'
        AND Exhibition.ends <= CURDATE()
ORDER BY
        Temperature.temperature DESC
LIMIT 5

,或者更好的是,将temperatures转换为UTF8

ALTER TABLE temperatures MODIFY COLUMN ref CHAR(36) CHARACTER SET utf8 NOT NULL, CHARACTER SET utf8

答案 1 :(得分:1)

您应该确保您的索引符合您的加入订单。如果您使用多个条件或多个连接,MySQL将查找匹配的索引。例如:

假设您的索引设置了以下字段:Exhibition.venue_id,Exhibition.active,Exhibition.ends

如果你的select语句是

SELECT fields FROM exhibitions WHERE Exhibition.venue_id > 10 AND Exhibition.active = 'T' AND Exhibition.ends < '2009/9/23'

然后应该使用你的索引。如果您更改条件的顺序,则可能不会使用您的索引,这可能会导致您看到的问题。

此外,如果您在活动字段上有一个索引,这是一个布尔值,它不会为您的搜索增加太多价值,除非通常会有较少的活动展览,然后是不活动的展览。如果您没有大量记录,优化器也可能会丢弃索引使用情况,因为它表明扫描更有效。

我会生成10,000条记录,然后重新运行。看看它是否仍然没有使用索引。

-Chris