MySQLの暗黙的な変換問題の解決

MySQLの暗黙的な変換問題の解決

1. 問題の説明

root@mysqldb 22:12: [xucl]> テーブル t1\G の作成を表示します
************************** 1. 行 ****************************
 表: t1
テーブルの作成: CREATE TABLE `t1` (
 `id` varchar(255) デフォルト NULL
) エンジン=InnoDB デフォルト文字セット=utf8
セット内の 1 行 (0.00 秒)
 
root@mysqldb 22:19: [xucl]> t1 から * を選択します。
+--------------------+
|id|
+--------------------+
| 204027026112927605 |
| 204027026112927603 |
| 2040270261129276 |
| 2040270261129275 |
| 100 |
| 101 |
+--------------------+
セット内の 6 行 (0.00 秒)

奇妙な現象:

root@mysqldb 22:19: [xucl]> id=204027026112927603 の t1 から * を選択します。
+--------------------+
|id|
+--------------------+
| 204027026112927605 |
| 204027026112927603 |
+--------------------+
セット内の 2 行 (0.00 秒)
640?wx_fmt=jpeg 

一体全体、204027026112927603 を確認したのに、なぜ 204027026112927605 も出てきたのでしょうか?

2. ソースコードの説明

コールスタックの関係は次のとおりです。

JOIN::exec()は実行エントリポイントであり、Arg_comparator::compare_real()は等価判定関数であり、以下のように定義される。

int Arg_comparator::compare_real()
{
 /*
 Bug#2338のもう一つの症状を修正。「Volatile」は次のように指示します。
 gccは80ビットIntel FPUレジスタからdouble値をフラッシュする前に
 比較を実行します。
 */
 揮発性ダブル val1、val2;
 val1 = (*a)->val_real();
 if (!(*a)->null_value)
 {
 val2 = (*b)->val_real();
 if (!(*b)->null_value)
 {
 (set_null)の場合
 所有者->null_value = 0;
 val1 < val2 の場合は -1 を返します。
 val1 == val2 の場合は 0 を返します。
 1 を返します。
 }
 }
 (set_null)の場合
 所有者->null_value = 1;
 -1 を返します。
}

比較手順を下図に示します。t1 テーブルの id 列が行ごとに読み取られ、val1 に格納されます。定数 204027026112927603 がキャッシュに存在し、その型は double (2.0402702611292762E+17) です。したがって、値が val2 に渡された後、val2=2.0402702611292762E+17 になります。

1行目までスキャンすると、204027026112927605をdouleに変換すると2.0402702611292762e17となり、等式が成立し、適格行であると判定され、スキャンが続行されます。同様に、204027026112927603も条件を満たしています。

文字列型数値から倍精度型数値への変換がオーバーフローするかどうかを検出するにはどうすればよいでしょうか。ここでテストしたところ、数値が16桁を超えると、倍精度型への変換は正確ではなくなりました。たとえば、20402702611292711は、20402702611292712と表現されます(図のval1に示すように)

MySQL 文字列を double に変換するための定義関数は次のとおりです。

{
 char buf[DTOA_BUFF_SIZE];
 ダブル解像度;
 DBUG_ASSERT(end != NULL && ((str != NULL && *end != NULL) ||
    (str == NULL && *end == NULL)) &&
  エラー != NULL);

 res = my_strtod_int(str、end、error、buf、sizeof(buf));
 戻り値 (*error == 0) ? res : (res < 0 ? -DBL_MAX : DBL_MAX);
}

実際の変換関数 my_strtod_int は dtoa.c にあります (複雑すぎるので、コメントを投稿してください)

/*
 IEEE 算術マシン用の strtod。
 
 このstrtodは入力された10進数に最も近い機械数を返します。
 文字列(またはerrnoをEOVERFLOWに設定)。同点の場合はIEEEラウンドイーブンで決着する。
 ルール。
 
 ウィリアム・D・クリンガーの論文「浮動小数点数の読み方」に大まかに触発されて
 「ポイント番号を正確に示す」[Proc. ACM SIGPLAN '90、pp. 92-101]。
 
 変更点:
 
 1. 必要なのは IEEE のみです (IEEE ダブル拡張ではありません)。
 2. 浮動小数点演算で済むケース
 クリンガーは失敗しました -- d * 10^n を計算しているとき
 小さな整数dと整数nが大きすぎる場合は
 22(kが最大となる整数)よりはるかに大きい
 10^kを正確に表現できる場合、
 1回の丸めだけで (d*10^k) * 10^(ek) を計算します。
 3. バイナリを少しずつ調整するのではなく
 その結果、難しいケースでは浮動小数点を使用する。
 調整を決定するための算術
 1ビット;本当に難しい場合にのみ、
 2番目の残差を計算します。
 4. 3. のため、10の累乗の大きな表は必要ありません。
 10の倍数(例えば10^kの小さな表)
 (0 <= k <= 22)。
*/

この場合、オーバーフローが発生しない場合をテストしてみましょう。

root@mysqldb 23:30: [xucl]> id=2040270261129276 の t1 から * を選択します。
+------------------+
|id|
+------------------+
| 2040270261129276 |
+------------------+
セット内の 1 行 (0.00 秒)
 
root@mysqldb 23:30: [xucl]> id=101 の場合、t1 から * を選択します。
+------+
|id|
+------+
| 101 |
+------+
セット内の 1 行 (0.00 秒)

結果は予想通りであり、この場合、正しい書き方は次のようになります。

root@mysqldb 22:19: [xucl]> id='204027026112927603' の t1 から * を選択します。
+--------------------+
|id|
+--------------------+
| 204027026112927603 |
+--------------------+
セット内の1行(0.01秒)

結論

暗黙的な型変換は避けてください。暗黙的な変換には、主に、一貫性のないフィールド型、in パラメータ内の複数の型、一貫性のない文字セット型または校正ルールなどが含まれます。

暗黙的な型変換により、インデックスが使用できなくなったり、クエリ結果が不正確になったりする可能性があるため、使用時には慎重に識別する必要があります。

フィールドを定義するときは、数値型を int または bigint として定義することをお勧めします。テーブルがリンクされている場合、関連付けられているフィールドは同じ型、文字セット、および照合ルールを維持する必要があります。

最後に、暗黙的な型変換についての公式サイトの説明を掲載しておきます。

1. 片方または両方の引数がNULLの場合、比較の結果はNULLになります(NULLセーフの場合を除く)。
<=> 等価比較演算子。NULL <=> NULL の場合、結果は true になります。変換は必要ありません。
2.比較演算の両方の引数が文字列の場合、それらは文字列として比較されます。
3. 両方の引数が整数の場合、整数として比較されます。
4. 16 進数値は、数値と比較されない場合はバイナリ文字列として扱われます。
5. 引数の1つがTIMESTAMPまたはDATETIME列で、もう1つの引数が
定数の場合、比較を実行する前に定数がタイムスタンプに変換されます。これは
これはODBCとの親和性を高めるために行われます。IN()の引数には適用されません。安全のため、常に
比較を行うときは、完全な日付時刻、日付、または時刻文字列を使用します。たとえば、最高の結果を得るには、
日付または時刻の値でBETWEENを使用する場合は、CAST()を使用して値を明示的に変換します。
必要なデータ型。
テーブルからの単一行のサブクエリは定数とはみなされません。たとえば、サブクエリが
DATETIME 値と比較する整数を返します。比較は 2 つの整数として行われます。
整数は時間値に変換されません。オペランドをDATETIME値として比較するには、
CAST() を使用して、サブクエリの値を DATETIME に明示的に変換します。
6. 引数の 1 つが 10 進数値の場合、比較は他の引数に依存します。
引数は、他の引数が小数または整数値の場合は小数値として比較され、
他の引数が浮動小数点値の場合、浮動小数点値になります。
7. それ以外の場合、引数は浮動小数点(実数)として比較されます。

要約する

上記は、編集者が紹介したMySQLの暗黙的な変換です。皆様のお役に立てれば幸いです。ご質問がある場合は、メッセージを残してください。編集者がすぐに返信します。また、123WORDPRESS.COM ウェブサイトをサポートしてくださっている皆様にも感謝申し上げます。
この記事が役に立ったと思われた方は、ぜひ転載していただき、出典を明記してください。ありがとうございます!

以下もご興味があるかもしれません:
  • MySQLの整数および文字列インデックスの無効化または暗黙的な変換に関する簡単な説明
  • MySQLの驚くべき暗黙の変換
  • MySQL 5.6 の「暗黙的な変換」によりインデックスが失敗し、データが不正確になる
  • MySQLの暗黙的な変換について話す
  • MySQL インデックス無効化の暗黙的な変換の問題

<<:  Centos7のシステム言語を簡体字中国語に変更する方法

>>:  jQuery カスタム虫眼鏡効果

推薦する

インデックススキャンを使用したMySQLソート

目次sakilaをインストールするインデックススキャンソートテーブル構造インデックススキャンをソート...

MySQL Undo ログと Redo ログの概要

目次元に戻すログUNDOログの生成と破棄UNDOログの保存元に戻すログ機能トランザクションの原子性の...

サラウンドリフレクションロード効果を実現するHTML+CSS

この記事では、主に html + css を使用してサラウンド リフレクション ローディング エフェ...

JS と Nodejs におけるイベント駆動型開発についての簡単な説明

目次イベント駆動型とパブリッシュ・サブスクライブ型ブラウザの JavaScript ではイベント駆動...

VMware仮想マシンの起動時に黒い画面が表示される問題を解決する

# VMware ハードディスクの起動優先順位を調整するステップ 1: 電源をオンにすると、BIOS...

MySQL のデータ型とフィールド属性の原理と使用法の詳細な説明

この記事では、MySQL のデータ型とフィールド属性について説明します。ご参考までに、詳細は以下の通...

docker を使用して Spring Boot をデプロイし、Skywalking に接続する方法

目次1. 概要1. スカイウォーキング入門2. スカイウォーキング建築3. スカイウォーキングはどの...

Vue 折りたたみ表示の複数行テキスト コンポーネントの実装コード

折りたたみ表示の複数行テキストコンポーネント複数行のテキスト コンポーネントを折りたたんで表示し、展...

MySQL 5.7.21 のインストールとパスワード設定のチュートリアル

MySQL5.7.21のインストールとパスワード設定のチュートリアルは次のとおりです。公式リファレン...

MySql SQL最適化のヒントの共有

ある日、内部結合を含む SQL ステートメントの実行速度はそれほど遅くはない (0.1 ~ 0.2)...

mysql5.7.14 解凍版インストールグラフィックチュートリアル

MySQL は、コミュニティ エディション (コミュニティ サーバー) とエンタープライズ エディシ...

Hタグはウェブページ制作において適切に使用すべきである

HTML タグには、ページのタイトルを処理するための特別なタグがあります。これらは h1、h2、h3...

CentOS 7 での Nginx ログタイミング分割の実装手順の詳細説明

1. 分割スクリプト (splitNginxLog.sh) を作成します。 * この例では、ログ分割...

React+TS を使用したシンプルな Jira プロジェクトを実装するためのベスト プラクティス

トレーニングのための一連のプロジェクト反応+ts内容は少ないですが、フックのカプセル化、ts ジェネ...

React プロジェクトで eslint の Baidu スタイルを使用する詳細な説明

1. Baidu Eslint Ruleプラグインをインストールする npm i -D eslint...