0

以下のクエリが、story_keywords テーブルでインデックス story_id を使用すると失敗するのはなぜですか?

mysql> EXPLAIN SELECT `stories`.*
    -> FROM (`stories`)
    -> JOIN `story_keywords` ON `story_keywords`.`story_id` = `stories`.`id`
    -> WHERE `image_full_url` != ''
    -> AND `order` != 0
    -> AND `news_type` IN ('movie', 'movie_review') 
    -> AND `keyword` IN ('topnews', 'toptablet') 
    -> GROUP BY `stories`.`id`
    -> ORDER BY `created` DESC, `order` DESC
    -> LIMIT 5 ;
+----+-------------+----------------+--------+---------------+---------+---------+---------------------------------------+------+----------------------------------------------+
| id | select_type | table          | type   | possible_keys | key     | key_len | ref                                   | rows | Extra                                        |
+----+-------------+----------------+--------+---------------+---------+---------+---------------------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | story_keywords | ALL    | story_id      | NULL    | NULL    | NULL                                  |   42 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | stories        | eq_ref | PRIMARY       | PRIMARY | 767     | entertainment.story_keywords.story_id |    1 | Using where                                  |
+----+-------------+----------------+--------+---------------+---------+---------+---------------------------------------+------+----------------------------------------------+
2 rows in set (0.00 sec)


mysql> show create table stories;
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stories | CREATE TABLE `stories` (
  `id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `news_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  `author` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `author_title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `image_caption` text COLLATE utf8_unicode_ci,
  `image_credit` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `image_full_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `body` text COLLATE utf8_unicode_ci,
  `summary` text COLLATE utf8_unicode_ci,
  `external_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `order` int(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> show create table story_keywords;
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table          | Create Table                                                                                                                                                                                                                                                                                                                      |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| story_keywords | CREATE TABLE `story_keywords` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `story_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `keyword` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `story_id` (`story_id`)
) ENGINE=MyISAM AUTO_INCREMENT=85 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
4

2 に答える 2

1

アントンは正しい方向に進んでいますが、問題はまだまだあると思います。OPに関する私のコメントが言うように、id列はおそらくINTタイプであるはずです。説明が示すように、オンの主キーの長さstoriesは767です。通常、INTタイプの場合、長さは1桁下になりますが、列がであるVARCHARため、長さは非常に長くなります。

主な問題に戻ると、、、、またはにインデックスがないためstories.news_typestories.orderオプティマイザは、最小の初期結果セットを生成するためstory_keywords.story_keywords、のフルスキャンを実行することにしました。story_keywordsこれらの列の1つにインデックスがあった場合、最初にそれを使用する可能性があります。クエリが使用できるインデックスを追加する場合、テーブル全体のスキャンを実行する必要はありません。

于 2012-11-14T15:34:20.867 に答える
1

これはおそらく、MySQLが、インデックスを使用する代わりに、story_keywordsテーブルからすべての行をフェッチしてそれらを結合する方が安価であると考えているためです。最初は奇妙に聞こえますが、テーブルに対して100個のインデックスルックアップを実行する必要があり、このテーブルに約100行しかない場合は、すべての行を読み取る方がコストが低くなります。説明は簡単です。インデックスルックアップ(BTREEインデックスの場合)はO(ln N)であり、N行の読み取りはO(N)です。明らかに、O(N)<N * O(ln N)。

それを証明するには、次のように、ストーリーから1行だけを選択してみてください(1行とは、テーブル全体を並べ替えて結果を制限するのではなく、1行を意味します;)。

SELECT `stories`.*
FROM (`stories`)
JOIN `story_keywords` ON `story_keywords`.`story_id` = `stories`.`id`
WHERE `stories`.id = SOMETHING

このクエリは、story_keywordsのインデックスに変わる可能性がはるかに高くなります。

これがあなたの質問に答えることを願っています:)

于 2012-11-14T15:17:04.240 に答える