6

MySQL 5.5.28。私には2つのテーブルがPersonありMessage、後者には前者への外部キーがあります。各テーブルにidは主キー列があり、PersonテーブルpersonIdには (一意に) インデックス付けされた列もあります。

以下のクエリはキー インデックスを利用する必要がありますが、MySQL では何らかの理由でテーブルpersonId全体をスキャンする必要があります。Message

mysql> EXPLAIN SELECT `m`.*
    -> から
    -> `Message` AS `m`
    -> 左結合
    -> `Person` AS `p` ON (`m`.`person` = `p`.`id`)
    ->どこで
    -> 'M002649397' は NULL または
    -> `p`.`personId` = 'M002649397';
+----+-------------+-------+--------+------------- --+---------+---------+----------------+--------+- ------------+
| | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 エクストラ |
+----+-------------+-------+--------+------------- --+---------+---------+----------------+--------+- ------------+
| | 1 | シンプル | メートル | すべて | ヌル | ヌル | ヌル | ヌル | 273220 | | |
| | 1 | シンプル | p | eq_ref | プライマリ | プライマリ | 8 | pcom.m.person | 1 | where | の使用
+----+-------------+-------+--------+------------- --+---------+---------+----------------+--------+- ------------+
2 行セット (0.00 秒)

しかし、句をコメントアウトすると'M002649397' IS NULL OR(結果には影響しません)、クエリが突然効率的になります。

mysql> EXPLAIN SELECT `m`.*
    -> から
    -> `Message` AS `m`
    -> 左結合
    -> `Person` AS `p` ON (`m`.`person` = `p`.`id`)
    ->どこで
    -> -- 'M002649397' は NULL または
    -> `p`.`personId` = 'M002649397';
+----+-------------+-------+-------+-------------- ------+--------------------+---------+-------+---- --+-------------+
| | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 エクストラ |
+----+-------------+-------+-------+-------------- ------+--------------------+---------+-------+---- --+-------------+
| | 1 | シンプル | p | 定数 | PRIMARY,personId | 個人ID | 767 | 定数 | 1 | インデックスの使用 |
| | 1 | シンプル | メートル | 参照 | FK9C2397E7A0F6ED11 | FK9C2397E7A0F6ED11 | 9 | 定数 | 3 | where | の使用
+----+-------------+-------+-------+-------------- ------+--------------------+---------+-------+---- --+-------------+
2行セット (0.01秒)

私の質問は、MySQL'M002649397' IS NULLが常に false であることを認識し、それを最適化し、巨大なテーブルのすべての行を不必要にスキャンする必要をなくすことができないのはなぜですか?

言い換えれば、MySQL オプティマイザはそれ'M002649397' IS NULLが常に false であることを認識していないのでしょうか? それとも、クエリ プランを作成するときにその最適化をクエリに適用できていないのでしょうか?

4

2 に答える 2

1

これは検証済みの MySQL バグです。

条件に対して 1 つの実行計画を持つことはできません。

WHERE (0 = 1) または p.personId = 'string_constant';

および別の実行計画:

WHERE p.personId = 'string_constant';

(0 = 1) は常に FALSE になるため、上記の 2 つのクエリは 100% 同一になります。

バグ レポート自体で、(0 = 1) OR が存在する場合の実行計画は、式が列と定数の等価のみである場合よりもはるかに悪いことがわかります。

*これはMariaDB で修正されていることに注意してください。

于 2013-09-10T03:58:50.643 に答える
1

実際、もっと興味深いのは、MySQL はこれを行うのに十分スマートであるとドキュメントに記載されていることです (こちらを参照)。

これは、「8.2.1.2.「デッド」コードの排除」という見出しの下にあるようです。

その理由は、開発者が「 is not null 」などの式をコードを作成するときに考慮していなかったためだと思います。ドキュメンテーションには、一定の伝播に基づく多くの例が示されています (x1 = 2 and x2 = x1になるx1 = 2 and x2 = 2)。 is nullおそらくこの状況で発生します。

于 2013-05-31T01:18:20.717 に答える