Beheben von Problemen mit impliziter MySQL-Konvertierung

Beheben von Problemen mit impliziter MySQL-Konvertierung

1. Problembeschreibung

root@mysqldb 22:12: [xucl]> zeige Tabelle erstellen t1\G
*************************** 1. Reihe ***************************
 Tabelle: t1
Tabelle erstellen: CREATE TABLE `t1` (
 `id` varchar(255) STANDARD NULL
) ENGINE=InnoDB STANDARD-CHARSET=utf8
1 Zeile im Satz (0,00 Sek.)
 
root@mysqldb 22:19: [xucl]> wähle * aus t1;
+--------------------+
|Ich würde|
+--------------------+
| 204027026112927605 |
| 204027026112927603 |
| 2040270261129276 |
| 2040270261129275 |
| 100 |
| 101 |
+--------------------+
6 Zeilen im Satz (0,00 Sek.)

Seltsames Phänomen:

root@mysqldb 22:19: [xucl]> wähle * von t1, wobei id=204027026112927603;
+--------------------+
|Ich würde|
+--------------------+
| 204027026112927605 |
| 204027026112927603 |
+--------------------+
2 Zeilen im Satz (0,00 Sek.)
640?wx_fmt=jpeg 

Was zur Hölle, ich habe 204027026112927603 überprüft, warum kam auch 204027026112927605 heraus?

2. Quellcode-Erklärung

Die Aufrufstapelbeziehung ist wie folgt:

JOIN::exec() ist der Ausführungseintrittspunkt und Arg_comparator::compare_real() ist eine Funktion zur Beurteilung gleicher Werte, die wie folgt definiert ist

int Arg_comparator::compare_real()
{
 /*
 Beheben Sie eine weitere Manifestation von Bug#2338. 'Volatile' weist an
 gcc zum Löschen von doppelten Werten aus 80-Bit-Intel-FPU-Registern vor
 Durchführen des Vergleichs.
 */
 flüchtiger doppelter Wert1, Wert2;
 val1= (*a)->val_real();
 wenn (!(*a)->null_wert)
 {
 val2 = (*b)->val_real();
 wenn (!(*b)->null_wert)
 {
 wenn (null setzen)
 Besitzer->Nullwert = 0;
 wenn (Wert1 < Wert2) returniere -1;
 wenn (Wert1 == Wert2) gibt 0 zurück;
 Rückgabe 1;
 }
 }
 wenn (null setzen)
 Besitzer->Nullwert = 1;
 Rückgabe -1;
}

Die Vergleichsschritte sind in der folgenden Abbildung dargestellt. Die ID-Spalte der t1-Tabelle wird zeilenweise gelesen und in val1 eingefügt. Die Konstante 204027026112927603 existiert im Cache und ihr Typ ist doppelt (2,0402702611292762E+17). Daher gilt nach der Übergabe des Wertes an val2: val2=2,0402702611292762E+17.

Beim Scannen bis zur ersten Zeile beträgt der in Doule umgewandelte Wert von 204027026112927605 2,0402702611292762e17. Die Gleichung wird erstellt, es wird festgestellt, dass es sich um eine qualifizierte Zeile handelt, und der Scan wird fortgesetzt. In ähnlicher Weise erfüllt auch 204027026112927603 die Bedingungen.

Wie kann man feststellen, ob die Konvertierung von Zahlen vom Typ String in den Typ Double überläuft? Nach dem Test hier ist die Konvertierung in den Typ Double nicht mehr genau, wenn die Zahl 16 Ziffern überschreitet. Beispielsweise wird 20402702611292711 als 20402702611292712 ausgedrückt (wie in val1 in der Abbildung gezeigt).

Die Definitionsfunktion zum Konvertieren von MySQL-Strings in Double lautet wie folgt:

{
 Zeichenpuffer [DTOA_BUFF_SIZE];
 doppelte Auflösung;
 DBUG_ASSERT(Ende != NULL && ((str != NULL && *Ende != NULL) ||
    (str == NULL && *end == NULL)) &&
  Fehler != NULL);

 res = my_strtod_int(str, Ende, Fehler, Puffer, Größe von(Puffer));
 Rückgabe (*Fehler == 0)? res: (res < 0? -DBL_MAX: DBL_MAX);
}

Die eigentliche Konvertierungsfunktion my_strtod_int befindet sich in dtoa.c (zu kompliziert, einfach einen Kommentar posten)

/*
 strtod für IEEE-Rechenmaschinen.
 
 Dieser Strtod gibt die nächste Maschinennummer zur eingegebenen Dezimalzahl zurück.
 string (oder setzt errno auf EOVERFLOW). Gleichstände werden durch die IEEE-Rundungsgleichung aufgelöst.
 Regel.
 
 Inspiriert von William D. Clingers Aufsatz „How to Read Floating
 Punktnummern genau angeben" [Proc. ACM SIGPLAN '90, Seiten 92-101].
 
 Änderungen:
 
 1. Wir benötigen nur IEEE (nicht IEEE Double-Extended).
 2. Wir kommen mit Gleitkommaarithmetik aus, wenn
 Clinger verpasst -- wenn wir d * 10^n berechnen
 für eine kleine Ganzzahl d und die Ganzzahl n ist nicht zu
 viel größer als 22 (die maximale Ganzzahl k, für die
 wir können 10^k genau darstellen), können wir vielleicht
 Berechnen Sie (d*10^k) * 10^(ek) mit nur einer Rundung.
 3. Anstatt einer schrittweisen Anpassung des Binärcodes
 Als Ergebnis verwenden wir im harten Fall Gleitkommazahlen
 Arithmetik zur Bestimmung der Anpassung innerhalb
 ein bisschen; nur in wirklich schwierigen Fällen müssen wir
 Berechnen Sie einen zweiten Rest.
 4. Wegen 3. brauchen wir keine große Tabelle mit Zehnerpotenzen
 für zehn zu e (nur einige kleine Tabellen, z. B. von 10^k
 für 0 <= k <= 22).
*/

In diesem Fall testen wir den Fall, in dem es keinen Überlauf gibt

root@mysqldb 23:30: [xucl]> wähle * von t1, wobei id=2040270261129276;
+------------------+
|Ich würde|
+------------------+
| 2040270261129276 |
+------------------+
1 Zeile im Satz (0,00 Sek.)
 
root@mysqldb 23:30: [xucl]> wähle * von t1, wo id=101;
+------+
|Ich würde|
+------+
| 101 |
+------+
1 Zeile im Satz (0,00 Sek.)

Das Ergebnis ist wie erwartet, und in diesem Fall sollte es korrekt so geschrieben werden:

root@mysqldb 22:19: [xucl]> wähle * von t1, wobei id='204027026112927603';
+--------------------+
|Ich würde|
+--------------------+
| 204027026112927603 |
+--------------------+
1 Zeile im Satz (0,01 Sek.)

Abschluss

Vermeiden Sie implizite Typkonvertierungen. Implizite Konvertierungen umfassen hauptsächlich inkonsistente Feldtypen, mehrere Typen im In-Parameter, inkonsistente Zeichensatztypen oder Korrekturleseregeln usw.

Implizite Typkonvertierungen können dazu führen, dass Indizes nicht verwendet werden können, die Abfrageergebnisse ungenau sind usw. Sie müssen sie daher bei der Verwendung sorgfältig identifizieren.

Es wird empfohlen, den numerischen Typ beim Definieren des Felds als int oder bigint zu definieren. Wenn die Tabelle verknüpft ist, müssen die zugehörigen Felder denselben Typ, Zeichensatz und dieselben Sortierregeln aufweisen.

Abschließend möchte ich die Beschreibung der impliziten Typkonvertierung auf der offiziellen Website veröffentlichen.

1. Wenn ein oder beide Argumente NULL sind, ist das Ergebnis des Vergleichs NULL, mit Ausnahme der NULL-sicheren
<=> Gleichheitsvergleichsoperator. Für NULL <=> NULL ist das Ergebnis wahr. Es ist keine Konvertierung erforderlich.
2. Wenn beide Argumente in einer Vergleichsoperation Zeichenfolgen sind, werden sie als Zeichenfolgen verglichen.
3. Wenn beide Argumente ganze Zahlen sind, werden sie als ganze Zahlen verglichen.
4. Hexadezimale Werte werden als Binärzeichenfolgen behandelt, wenn sie nicht mit einer Zahl verglichen werden.
5. Wenn eines der Argumente eine TIMESTAMP- oder DATETIME-Spalte ist und das andere Argument eine
Konstante wird die Konstante vor dem Vergleich in einen Zeitstempel umgewandelt. Dies ist
getan, um ODBC-freundlicher zu sein. Dies wird nicht für die Argumente von IN() getan. Um sicher zu gehen, immer
Verwenden Sie bei Vergleichen vollständige Datums- und Uhrzeitzeichenfolgen. Um beispielsweise die beste
Ergebnisse bei der Verwendung von BETWEEN mit Datums- oder Zeitwerten, verwenden Sie CAST(), um die Werte explizit zu konvertieren in
der gewünschte Datentyp.
Eine einzeilige Unterabfrage aus einer oder mehreren Tabellen wird nicht als Konstante betrachtet. Wenn beispielsweise eine Unterabfrage
Gibt eine Ganzzahl zurück, die mit einem DATETIME-Wert verglichen werden soll. Der Vergleich erfolgt als zwei Ganzzahlen.
Die Ganzzahl wird nicht in einen Zeitwert umgewandelt. Um die Operanden als DATETIME-Werte zu vergleichen,
verwenden Sie CAST(), um den Unterabfragewert explizit in DATETIME zu konvertieren.
6. Wenn eines der Argumente ein Dezimalwert ist, hängt der Vergleich vom anderen Argument ab.
Die Argumente werden als Dezimalwerte verglichen, wenn das andere Argument ein Dezimal- oder Integerwert ist, oder als
Gleitkommawerte, wenn das andere Argument ein Gleitkommawert ist.
7. In allen anderen Fällen werden die Argumente als Gleitkommazahlen (reelle Zahlen) verglichen.

Zusammenfassen

Das Obige ist die vom Editor eingeführte implizite MySQL-Konvertierung. Ich hoffe, es wird allen helfen. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und der Editor wird Ihnen rechtzeitig antworten. Ich möchte auch allen für ihre Unterstützung der Website 123WORDPRESS.COM danken!
Wenn Sie diesen Artikel hilfreich finden, können Sie ihn gerne abdrucken und dabei bitte die Quelle angeben. Vielen Dank!

Das könnte Sie auch interessieren:
  • Eine kurze Diskussion über die Ungültigkeitserklärung oder implizite Konvertierung von MySQL-Integer- und String-Indizes
  • Die überraschende implizite Konvertierung von MySQL
  • „Implizite Konvertierung“ von MySQL 5.6 führt zu Indexfehlern und ungenauen Daten
  • Sprechen Sie über implizite Konvertierung in MySQL
  • Problem der impliziten Konvertierung der MySQL-Indexungungültigkeit

<<:  So ändern Sie die Systemsprache von CentOS7 in vereinfachtes Chinesisch

>>:  jQuery benutzerdefinierter Lupeneffekt

Artikel empfehlen

Zusammenfassung der praktischen Erfahrungen zu HTML-Wissenspunkten

1. Das Tabellen-Tag ist Tabelle, tr ist Zeile, td ...

Eine kurze Analyse von MySQL-Verbindungen und -Sammlungen

Join-Abfrage Eine Join-Abfrage bezieht sich auf e...

Docker-Bindung mit fester IP/Hostübergreifender Container-Gegenzugriffsvorgang

Vorwort Bisher waren statische IPs, die über Pipe...

Eine einfache Möglichkeit zum Erstellen einer Docker-Umgebung

Lassen Sie uns zunächst verstehen, was Docker ist...

mysql 8.0.19 winx64.zip Installations-Tutorial

Dieser Artikel zeichnet das Installationstutorial...

Tutorial zur Installation der Dekomprimierungsversion von MySQL 8.0.12

In diesem Artikel finden Sie das Installations-Tu...

Detaillierte Erläuterung der gespeicherten Prozedur „MySql View Trigger“

Sicht: Wenn eine temporäre Tabelle wiederholt ver...

So konfigurieren Sie den Nginx-Lastausgleich

Inhaltsverzeichnis Nginx-Lastausgleichskonfigurat...

js zur Realisierung einer einfachen Scheibenuhr

In diesem Artikel wird der spezifische Code von j...