MySQL 8.0 リファレンスマニュアル MySQL NDB Cluster 8.0 を含む

このページは機械翻訳したものです。

8.2.1.20 関数コールの最適化

MySQL 関数は、内部的に決定論的または非決定的としてタグ付けされます。 関数に決定性がない状態とは、引数の値が固定されていても、呼び出しごとに異なる結果が返されることがある場合です。 非決定的関数の例: RAND()UUID()

関数が非決定的にタグ付けされている場合、WHERE 句でのその関数への参照は、行ごと (あるテーブルから選択する場合) または行の組合せごと (複数テーブル結合から選択する場合) に評価されます。

MySQL では、引数がテーブルのカラムであるか定数値であるかにかかわらず、引数のタイプに基づいて関数を評価するタイミングも決定されます。 テーブルのカラムを引数として取る決定的関数は、そのカラムの値が変更されるたびに評価される必要があります。

非決定的関数は、クエリーのパフォーマンスに影響を与える可能性があります。 たとえば、一部の最適化を使用できない場合や、より多くのロックが必要になる場合があります。 次の説明では、RAND() を使用しますが、他の非決定的関数にも適用されます。

テーブル t に次の定義があるとします:

CREATE TABLE t (id INT NOT NULL PRIMARY KEY, col_a VARCHAR(100));

次の 2 つのクエリーについて考えてみます:

SELECT * FROM t WHERE id = POW(1,2);
SELECT * FROM t WHERE id = FLOOR(1 + RAND() * 49);

主キーに対する等価比較のため、両方のクエリーで主キー参照が使用されているように見えますが、これは最初のクエリーにのみ当てはまります:

非決定の影響は、SELECT ステートメントに限定されません。 次の UPDATE ステートメントでは、非決定的関数を使用して、変更する行を選択します:

UPDATE t SET col_a = some_expr WHERE id = FLOOR(1 + RAND() * 49);

主キーが式と一致する単一の行のみを更新することを意図しています。 ただし、id カラムの値および RAND() 順序の値によっては、ゼロ、1 または複数の行が更新される場合があります。

ここで説明した動作は、パフォーマンスとレプリケーションに影響します:

問題は、RAND() 関数がテーブルのすべての行に対して 1 回評価されるという事実から発生します。 複数の関数の評価を回避するには、次のいずれかの方法を使用します:

前述のように、WHERE 句の非決定的な式によって最適化が妨げられ、テーブルスキャンが発生する可能性があります。 ただし、他の式が決定的である場合は、WHERE 句を部分的に最適化できます。 例:

SELECT * FROM t WHERE partial_key=5 AND some_column=RAND();

オプティマイザが partial_key を使用して選択された行セットを減らすことができる場合、RAND() の実行回数が少なくなり、最適化に対する非決定の影響が低下します。