MySQL の驚くべき暗黙的変換を見てみましょう

coldplay.xixi
リリース: 2021-01-13 09:20:41
転載
2011 人が閲覧しました

Mysql チュートリアルのコラムでは、関連する暗黙的変換を紹介します

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)
ログイン後にコピー

MySQL の驚くべき暗黙的変換を見てみましょう

#何だ、小切手は明らかに 204027026112927603 なのに、なぜ 204027026112927605 も出てくるのでしょう

2. ソースコードの説明

スタック呼び出し関係は次のとおりです:

MySQL の驚くべき暗黙的変換を見てみましょう

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.

MySQL の驚くべき暗黙的変換を見てみましょう

最初の行をスキャンすると、204027026112927605 をドゥール換算した値は 2.0402702611292762e17 となり、方程式が成立し、条件を満たす行と判断されます。理由 204027026112927603 は、

MySQL の驚くべき暗黙的変換を見てみましょう

ドゥール型に変換された文字列型の数値がオーバーフローするかどうかを検出する方法?ここでテストした後、数値が 16 桁を超えた場合にも一致します。の場合、「The double type is selected inaccurate」に変換されます。たとえば、20402702611292711 は、20402702611292712 (図の val1)

MySQL の驚くべき暗黙的変換を見てみましょう

MySQL の驚くべき暗黙的変換を見てみましょう

と表現されます。

MySQL 文字列変換 double への定義関数は次のとおりです:

{
  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&#39;s paper "How to Read Floating
  Point Numbers Accurately" [Proc. ACM SIGPLAN &#39;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&#39;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&#39;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=&#39;204027026112927603&#39;;
+--------------------+
| id                 |
+--------------------+
| 204027026112927603 |
+--------------------+
1 row in set (0.01 sec)
ログイン後にコピー
## であるはずです。

# 3. 結論

  1. 暗黙的な型変換を避ける 暗黙的な変換の種類には主にフィールド型の不一致、複数の型を含むパラメータ、文字セットの不一致などが含まれます。

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

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

  4. #最後に、暗黙的な型変換に関する手順を公式 Web サイトから投稿してください

    #えー

以上がMySQL の驚くべき暗黙的変換を見てみましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:csdn.net
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート