2017-11-03 16 views
1

MySQLクエリのselect文に複数の同じ式が存在する場合、サーバは式をもう一度計算するか、それを再利用しますか?MySQLはどのように列を選択しますか..?

例:

選択列1、上記のクエリでは 'ADAMの%' のような上部(列1)

表からNAME1として(列1)上部上部(列1を行い)式は1回または2回計算されます..?

また、私はこの文書の詳細を見つけることができますか?このクエリで

TIA

+0

説明プランを確認しましたか? –

+0

最後の編集をロールバックしてください(私は自分の電話ではできません)。 OPの特異性の一部は編集によって失われます。 OPはSELECT句の同じ列について話していません。 OPの質問は2つの 'upper()'呼び出しに関するものです。 – mickmackusa

+0

WHERE句のような式を使用すると、クエリでインデックスを最適化することが不可能になります。そのため、選択リストの余分な評価のコストは、あなたの心配ではありません! –

答えて

1

私はこの質問に答えるいくつかのポイントがあります。

あなたの質問に答えるために最適化なし:いいえ、私はMySQLは、それはWHERE句で関数を評価した、既にしていることを「記憶」という任意のレポートを読むことがありません。 WHERE句と選択リストを別々に評価します。

一方、MySQLは確定的な定数関数を評価します。式はすべての行で同じ定数値に評価されます)、これはより一般的に有用なパフォーマンス改善です。 https://dev.mysql.com/doc/refman/5.7/en/function-optimization.html

UPPER()は高価ではありませんマイクロ最適化しないでくださいを参照してください。この機能を100万回実行しても、0.04秒しかかかりません。これは文字列リテラルの評価に要する時間以上ですが、まだ目立ちません。

mysql> select benchmark(1000000, 'adam'); 
+----------------------------+ 
| benchmark(1000000, 'adam') | 
+----------------------------+ 
|       0 | 
+----------------------------+ 
1 row in set (0.01 sec) 

mysql> select benchmark(1000000, upper('adam')); 
+-----------------------------------+ 
| benchmark(1000000, upper('adam')) | 
+-----------------------------------+ 
|         0 | 
+-----------------------------------+ 
1 row in set (0.04 sec) 

ケース小文字を区別しないであなたは、大文字と小文字を区別しない照合を使用している場合(これがデフォルトです)、あなたが表示され、クエリでは全くUPPER()を使用する必要はありません

を検索します。

"ci"照合のため、LIKE述語は、デフォルトで大文字と小文字を区別しない比較を行います。

mysql> show variables like '%collation%'; 
+----------------------+--------------------+ 
| Variable_name  | Value    | 
+----------------------+--------------------+ 
| collation_connection | utf8mb4_0900_ai_ci | 
| collation_database | utf8_general_ci | 
| collation_server  | utf8_general_ci | 
+----------------------+--------------------+ 

mysql> select 'abc' like 'ABC'; 
+------------------+ 
| 'abc' like 'ABC' | 
+------------------+ 
|    1 | 
+------------------+ 

Sargability

あなたのWHERE句で表現比較でUPPER()の評価の性能にはるかに大きなコストがあります。

テーブルに100万行が含まれていて、そのうちの1000個だけが、探している 'ADAM%'パターンと一致しているとします。

mysql> EXPLAIN SELECT UPPER(column1) AS name1 FROM MyTable 
     WHERE UPPER(column1) LIKE 'ADAM%'\G 

      id: 1 
    select_type: SIMPLE 
     table: MyTable 
    partitions: NULL 
     type: index 
possible_keys: NULL 
      key: column1 
     key_len: 153 
      ref: NULL 
     rows: 735250 <-- this is an order-of-magnitude estimate 
    filtered: 100.00 
     Extra: Using where; Using index 

これは、インデックスを使用するため、クエリが100万行を読んで、そしてすべての行のためのWHERE句の式を評価させ、テーブル・スキャンを強制することはできません。このようなWHERE句を使用しました。裸カラム使用一方

mysql> EXPLAIN SELECT UPPER(column1) AS name1 FROM MyTable 
     WHERE column1 LIKE 'ADAM%'\G 

      id: 1 
    select_type: SIMPLE 
     table: MyTable 
    partitions: NULL 
     type: range 
possible_keys: column1 
      key: column1 
     key_len: 153 
      ref: NULL 
     rows: 1000 <-- much better! 
    filtered: 100.00 
     Extra: Using where; Using index 

は(指標が存在する場合)、列1のインデックスを使用し、唯一の一致する行を調べ。 UPPER()を100万回評価するだけでなく、行の99.9%を調べることも避けてください。

念頭に置いておくべきことは、sargabilityと呼ばれています。つまり、検索式を指定すると、MySQLはインデックスを使用して値を検索できます。関数呼び出しの中に列を置くと、sargabilityが損なわれる。

式インデックス

MySQLの仮想列を助けることができる場合は、コメントに尋ねました。私が上に書いたように、これは必要ではありません。しかし、引数のために、ここでは取引:

MySQLはexpression indexes in PostgreSQLのような表現インデックスを持っていません(PostgreSQLでは、インデックス定義に式を含めると、WHERE句で同じ式を使用すると分かります)インデックスを使用する)。

MySQLには多少の違いがあります。つまり、式に基づいて仮想列を定義してから、その仮想列にインデックスを付けることができます。しかし、あなたはインデックス定義に式を入れません。

mysql> ALTER TABLE MyTable 
     ADD COLUMN column1_upper VARCHAR(50) AS (UPPER(column1)), 
     ADD KEY (column1_upper); 

新しい列を参照するときに、インデックスを使用することがあります。しかし、列が定義されている式を使用しないで、sargabilityの通常の規則と同様に、単に列名をそのまま使用します。

+0

非常に有益な投稿でした。ありがとうございました。 –

2

Select Column1, upper(Column1) as name1 
from Table 
where upper(Column1) like 'ADAM%'; 

私はupper(Column1)が二回に評価されていることを推測します。いくつかのデータベースは、共通の部分式を見つけることができる洗練された最適化を持っています。私はMySQLがそうは思わない。

しかし、それは違いはありません。 upper()は、データを読み取ることと比較して比較的安価であり、likeと比較する必要があります。これは特に、クエリがインデックスを使用できないため完全なテーブルスキャンを実行する必要があるためです。

MySQLはこれを回避します。あなたがhavingを使用している場合、それは一度だけ計算を行う必要があります。

Select Column1, upper(Column1) as name1 
from Table 
having upper(Column1) like 'ADAM%'; 

これはMySQLの拡張機能です。

+0

MySQLはこれを回避します。あなたが持っている場合 どここのドキュメントを見つけることができます..? Pls、ここで私を助けてください。ありがとう。 –

0
句はSELECT句の前に評価され&とは論理的

、およびいくつかのデータベースが(Oracleは、私が知っSQL Serverが)再利用できる計算値(でもcase式)に述語の別名を割り当てることができます後で説明/実行計画に反映されます。 MySQLの説明計画では、私が知っている情報のレベルを明らかにしていないので、MySQLがこれに対応できるかどうかは確信できません。

さらに例は、UPPERやGROUP BY句とSELECT句の両方で繰り返される大文字小文字の表現のような「複雑な」ものです。これは、SELECTより前にGROUP BYが実行されるため、SELECT節です。 (HAVING節「トリック」が以前に提案された理由があるかもしれません。)

したがって、これを判断する論理的な句の動作順序を理解することは非常に有用だと思います。例えばA Beginner’s Guide to the True Order of SQL Operationsあなたの特定の質問にはっきりと答えることはできません。

関連する問題