web-dev-qa-db-ja.com

MySQLは、インデックスを追加してから削除した後、異なる結果を説明します

奇妙な振る舞いに遭遇します。次の構造を持つ2つのテーブルproductproduct_descriptionがあります(簡潔にするために、いくつかの無関係な列は省略されています)。

CREATE TABLE `oc_product` (
  `product_id` int(11) NOT NULL AUTO_INCREMENT,
  `price` decimal(15,4) NOT NULL DEFAULT '0.0000',
  PRIMARY KEY (`product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `oc_product_description` (
  `product_id` int(11) NOT NULL,
  `language_id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `description` text NOT NULL,
  PRIMARY KEY (`product_id`,`language_id`),
  KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

language_idには2つの可能な値があるため、各製品にはproduct_descriptionテーブルに正確に2つの対応する行があります。次のクエリを実行すると、product_description rowsの値に驚きました。

EXPLAIN
SELECT p.product_id
FROM oc_product p
  JOIN oc_product_description pd USING (product_id)
WHERE p.product_id = 12345;

+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | p     | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | Using index |
|  1 | SIMPLE      | pd    | NULL       | ref   | PRIMARY       | PRIMARY | 4       | const |   60 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+

主キーはそのままで問題ないはずですが、好奇心から、product_description列に対してのみproduct_idに単一のインデックスを追加しました。

ALTER TABLE `oc_product_description` ADD INDEX (`product_id`);

Explainクエリを再試行して異なる結果が得られましたが、奇妙なことに、同じキーが使用されています。

+----+-------------+-------+------------+-------+--------------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys      | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+--------------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | p     | NULL       | const | PRIMARY            | PRIMARY | 4       | const |    1 |   100.00 | Using index |
|  1 | SIMPLE      | pd    | NULL       | ref   | PRIMARY,product_id | PRIMARY | 4       | const |    2 |   100.00 | Using index |
+----+-------------+-------+------------+-------+--------------------+---------+---------+-------+------+----------+-------------+

次に、追加のインデックスを削除します。

ALTER TABLE `oc_product_description` DROP INDEX `product_id`;

そして、同じクエリを再度実行します。

+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | p     | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | Using index |
|  1 | SIMPLE      | pd    | NULL       | ref   | PRIMARY       | PRIMARY | 4       | const |    2 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+

突然、行数が通常に戻りました。同じデータベースのバックアップを使用して、同じ動作を再現することができました。以前にOPTIMIZE TABLE oc_product_descriptionREPAIR TABLE oc_product_descriptionの両方を試しましたが、60に追加のインデックスを追加(および削除)するまで、以前と同じproduct_id行数です。 。

一体何がここで起こっているのか誰かが説明できますか? MySQL Serverバージョン5.7.18-0ubuntu0.16.04.1-log(Ubuntu)を使用しています

2
billynoah

本当にInnoDBに切り替える必要があります。 MyISAMには、ここ数年、実質的に何の努力も払われていません。

「2」と「60」は大きく違うことに同意します。ただし、残りのEXPLAIN出力は、その数に基づいて何も変更されていないことを意味します。

あなたの質問はかなり人工的です。 1つの製品のすべての翻訳を取得しますが、これは役に立たないようです。また、すでに知っている情報(product_id)も取得します。実際のクエリに切り替えてください。その時何か面白いことがあるかもしれません。

1
Rick James