重要
このページは英語版のページを機械翻訳しています。原文はこちらからご覧ください。

暗黙的な型変換を回避する

このドキュメントでは、TiDBでの暗黙的な型変換の規則と考えられる結果、および暗黙的な型変換を回避する方法を紹介します。

変換規則

SQLステートメントの述語の両側のデータ型が一致しない場合、TiDBは、述語操作のために、片側または両側のデータ型を互換性のあるデータ型に暗黙的に変換します。

TiDBでの暗黙的な型変換のルールは次のとおりです。

  • 一方または両方の引数がNULLの場合、比較の結果はNULLになります。 NULL <=> NULLはtrueになるため、NULLセーフ<=>の同等の比較演算子は変換を必要としません。
  • 比較操作の両方の引数が文字列の場合、それらは文字列として比較されます。
  • 両方の引数が整数の場合、それらは整数として比較されます。
  • 数値との比較が行われない場合、16進値は2進文字列として扱われます。
  • 引数の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)です。実行プランでは、暗黙的な型変換が行われ、10進フィールドと文字列定数の両方がdouble型に変換されます。ダブルタイプの精度は10進数ほど高くないため、精度が低下します。この場合、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)

実行結果の簡単な説明:上記の実行は間違った結果をもたらします。