Mysql チュートリアルのコラムでは、関連する暗黙的変換を紹介します
その他の関連する無料学習 推奨: mysql チュートリアル #(ビデオ)
1. 問題の説明
root@mysqldb 22:12: [xucl]> show create table t1\G *************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `id` varchar(255) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) root@mysqldb 22:19: [xucl]> select * from t1; +--------------------+ | id | +--------------------+ | 204027026112927605 | | 204027026112927603 | | 2040270261129276 | | 2040270261129275 | | 100 | | 101 | +--------------------+ 6 rows in set (0.00 sec)
奇妙な現象:
root@mysqldb 22:19: [xucl]> select * from t1 where id=204027026112927603; +--------------------+ | id | +--------------------+ | 204027026112927605 | | 204027026112927603 | +--------------------+ 2 rows in set (0.00 sec)
#何だ、小切手は明らかに 204027026112927603 なのに、なぜ 204027026112927605 も出てくるのでしょう
2. ソースコードの説明
スタック呼び出し関係は次のとおりです:
JOIN::exec( )
は実行のエントリポイント、 Arg_comparator::compare_real()
は等価性判定の関数で、その定義は次のとおりです
int Arg_comparator::compare_real() { /* Fix yet another manifestation of Bug#2338. 'Volatile' will instruct gcc to flush double values out of 80-bit Intel FPU registers before performing the comparison. */ volatile double val1, val2; val1= (*a)->val_real(); if (!(*a)->null_value) { val2= (*b)->val_real(); if (!(*b)->null_value) { if (set_null) owner->null_value= 0; if (val1 < val2) return -1; if (val1 == val2) return 0; return 1; } } if (set_null) owner->null_value= 1; return -1; }
比較手順は図のとおりです。下図、一行ずつ読み込む val1にはt1テーブルのidカラムが配置されており、定数204027026112927603がキャッシュに存在し、その型がdouble(2.0402702611292762E 17)なので、ここでval2に値を渡すと、val2=2.0402702611292762となります。 E17.
最初の行をスキャンすると、204027026112927605 をドゥール換算した値は 2.0402702611292762e17 となり、方程式が成立し、条件を満たす行と判断されます。理由 204027026112927603 は、
ドゥール型に変換された文字列型の数値がオーバーフローするかどうかを検出する方法?ここでテストした後、数値が 16 桁を超えた場合にも一致します。の場合、「The double type is selected inaccurate」に変換されます。たとえば、20402702611292711 は、20402702611292712 (図の val1)
と表現されます。{ char buf[DTOA_BUFF_SIZE]; double res; DBUG_ASSERT(end != NULL && ((str != NULL && *end != NULL) || (str == NULL && *end == NULL)) && error != NULL); res= my_strtod_int(str, end, error, buf, sizeof(buf)); return (*error == 0) ? res : (res < 0 ? -DBL_MAX : DBL_MAX); }
実際の変換関数 my_strtod_int
は dtoa.c にあります (複雑すぎます。コメント)
/* strtod for IEEE--arithmetic machines. This strtod returns a nearest machine number to the input decimal string (or sets errno to EOVERFLOW). Ties are broken by the IEEE round-even rule. Inspired loosely by William D. Clinger's paper "How to Read Floating Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. Modifications: 1. We only require IEEE (not IEEE double-extended). 2. We get by with floating-point arithmetic in a case that Clinger missed -- when we're computing d * 10^n for a small integer d and the integer n is not too much larger than 22 (the maximum integer k for which we can represent 10^k exactly), we may be able to compute (d*10^k) * 10^(e-k) with just one roundoff. 3. Rather than a bit-at-a-time adjustment of the binary result in the hard case, we use floating-point arithmetic to determine the adjustment to within one bit; only in really hard cases do we need to compute a second residual. 4. Because of 3., we don't need a large table of powers of 10 for ten-to-e (just some small tables, e.g. of 10^k for 0 <= k <= 22). */
この場合、オーバーフローなしのテストの結果
root@mysqldb 23:30: [xucl]> select * from t1 where id=2040270261129276; +------------------+ | id | +------------------+ | 2040270261129276 | +------------------+ 1 row in set (0.00 sec) root@mysqldb 23:30: [xucl]> select * from t1 where id=101; +------+ | id | +------+ | 101 | +------+ 1 row in set (0.00 sec)
は期待どおりであり、この場合、正しい記述方法は
root@mysqldb 22:19: [xucl]> select * from t1 where id='204027026112927603'; +--------------------+ | id | +--------------------+ | 204027026112927603 | +--------------------+ 1 row in set (0.01 sec)
# 3. 結論
暗黙的な型変換を避ける 暗黙的な変換の種類には主にフィールド型の不一致、複数の型を含むパラメータ、文字セットの不一致などが含まれます。
暗黙的な型変換により、インデックスが使用できなくなったり、クエリ結果が不正確になったりする可能性があるため、慎重にスクリーニングする必要があります。使用する場合は、
フィールドを定義するときに、数値型を int または bigint として定義することをお勧めします。テーブルが関連付けられている場合、関連付けられたフィールドは維持される必要があります。同じ型、文字セット、および照合ルール
#えー
以上がMySQL の驚くべき暗黙的変換を見てみましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。