暗黙的な型変換を避ける
このドキュメントでは、TiDB における暗黙的な型変換のルールと考えられる結果、および暗黙的な型変換を回避する方法について説明します。
変換ルール
SQL ステートメントの述語の両側のデータ型が一致しない場合、TiDB は、述語操作のために、一方または両方の側のデータ型を互換性のあるデータ型に暗黙的に変換します。
TiDB での暗黙的な型変換のルールは次のとおりです。
- 引数の 1 つまたは両方が
NULL
の場合、比較の結果はNULL
になります。NULL 安全な<=>
同等の比較演算子では、 NULL<=>
NULL の結果がtrue
になるため、変換は必要ありません。 - 比較演算の両方の引数が文字列の場合、それらは文字列として比較されます。
- 両方の引数が整数の場合、それらは整数として比較されます。
- 数値による比較が行われない場合、16 進数値はバイナリ文字列として扱われます。
- 引数の 1 つが 10 進数値の場合、比較は他の引数によって決まります。他の引数が 10 進数値または整数値の場合、引数は 10 進数値と比較されます。他の引数が浮動小数点数値の場合、引数は浮動小数点数値と比較されます。
- 引数の 1 つが
TIMESTAMP
またはDATETIME
列で、もう 1 つの引数が定数の場合、比較が実行される前に定数がタイムスタンプに変換されます。 - それ以外の場合、引数は浮動小数点数 (
DOUBLE
型) として比較されます。
暗黙的な型変換によって生じる結果
暗黙的な型変換により、人間とコンピューターの相互作用の使いやすさが向上します。ただし、アプリケーション コードでは暗黙的な型変換を使用しないでください。次のような問題が発生する可能性があります。
- インデックスの無効
- 精度の低下
インデックスの無効
次のケースでは、 account_id
主キーであり、そのデータ型はvarchar
です。実行プランでは、この SQL ステートメントには暗黙的な型変換があり、インデックスを使用できません。
DESC SELECT * FROM `account` WHERE `account_id`=6010000000009801;
+-------------------------+----------------+-----------+---------------+------------------------------------------------------------+
| id | estRows | task | access object | operator info |
+-------------------------+----------------+-----------+---------------+------------------------------------------------------------+
| TableReader_7 | 8000628000.00 | root | | data:Selection_6 |
| └─Selection_6 | 8000628000.00 | cop[tikv] | | eq(cast(findpt.account.account_id), 6.010000000009801e+15) |
| └─TableFullScan_5 | 10000785000.00 | cop[tikv] | table:account | keep order:false |
+-------------------------+----------------+-----------+---------------+------------------------------------------------------------+
3 rows in set (0.00 sec)
実行結果の簡単な説明: 上記の実行プランから、 Cast
演算子が表示されます。
精度の低下
次のケースでは、 a
フィールドのデータ型はdecimal(32,0)
です。実行プランでは暗黙的な型変換が発生し、decimal フィールドと文字列定数の両方が double 型に変換されます。double 型の精度は、decimal ほど高くないため、精度が低下します。この場合、SQL ステートメントは、結果セットを範囲外に誤ってフィルター処理します。
DESC SELECT * FROM `t1` WHERE `a` BETWEEN '12123123' AND '1111222211111111200000';
+-------------------------+---------+-----------+---------------+-------------------------------------------------------------------------------------+
| id | estRows | task | access object | operator info |
+-------------------------+---------+-----------+---------------+-------------------------------------------------------------------------------------+
| TableReader_7 | 0.80 | root | | data:Selection_6 |
| └─Selection_6 | 0.80 | cop[tikv] | | ge(cast(findpt.t1.a), 1.2123123e+07), le(cast(findpt.t1.a), 1.1112222111111112e+21) |
| └─TableFullScan_5 | 1.00 | cop[tikv] | table:t1 | keep order:false, stats:pseudo |
+-------------------------+---------+-----------+---------------+-------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)
実行結果の簡単な説明: 上記の実行プランから、 Cast
演算子が表示されます。
SELECT * FROM `t1` WHERE `a` BETWEEN '12123123' AND '1111222211111111200000';
+------------------------+
| a |
+------------------------+
| 1111222211111111222211 |
+------------------------+
1 row in set (0.01 sec)
実行結果の簡単な説明: 上記の実行では間違った結果が生成されます。
ヘルプが必要ですか?
不和またはスラック 、またはサポートチケットを送信するについてコミュニティに質問してください。