Die implizite Konvertierung von MySQL muss bekannt und verstanden sein

In der Produktionsumgebung gibt es häufig einige implizite Typkonvertierungen, die dazu führen, dass SQL-Indizes fehlschlagen und eine extrem schlechte Leistung erbringen, was sich wiederum auf die Clusterlast und das Geschäft auswirkt. In diesem Artikel werden häufige Szenarien der impliziten Konvertierung zusammengefasst. Versuchen Sie, die implizite SQL-Konvertierung in der Produktion zu vermeiden.

Autor: Zhang Luodan interessiert sich leidenschaftlich für Datenbanktechnologie und erforscht sie ständig. Er hofft, in Zukunft ausführlichere Artikel schreiben und wertvollere Inhalte veröffentlichen zu können!

Produziert von der Aikeson Open Source Community. Bitte kontaktieren Sie den Herausgeber und geben Sie die Quelle für den Nachdruck an.

Dieser Artikel umfasst etwa 3.000 Wörter und die Lektüre dauert voraussichtlich 10 Minuten.

Zu den häufigsten Szenarios, in denen SQL implizite Konvertierungen generiert, gehören:

  1. Implizite Konvertierung von Datentypen
  2. Implizite Konvertierung von Zeichensätzen

Dabei wird die Zeichensatzkonvertierung, insbesondere in Tabellenverbindungsszenarien und gespeicherten Prozeduren, leicht übersehen.

Hinweis: Der Zeichensatz ist die Kodierungsregel für Zeichentypdaten. Für numerische Typen ist keine Konvertierung des Zeichensatzes erforderlich.

Implizite Konvertierung von Datentypen

Testtabellenstruktur

t1Die Tabellenfelder asind vom Typ VARCHAR und t2die Tabellenfelder avom Typ INT.

mysql> show create database test1\G
*************************** 1. row ***************************
       Database: test1
Create Database: CREATE DATABASE `test1` /*!40100 DEFAULT CHARACTER SET utf8 */
1 row in set (0.00 sec)
mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) NOT NULL,
  `a` varchar(20) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> show create table t2\G
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `id` int(11) NOT NULL,
  `a` int(11) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

Beispiel für eine einzelne Tabelle

Hierbei ist zu beachten, dass es die folgenden zwei Arten von Konvertierungen gibt:

  1. Wenn der Feldtyp ein Zeichenfolgentyp und der Parameter eine Ganzzahl ist, schlägt der Index fehl.
  2. Wenn der Feldtyp eine Ganzzahl und der eingehende Parameter ein Zeichenfolgentyp ist, führt dies nicht zu einem Indexfehler.

Dies liegt daran, dass MySQL beim Vergleich von Zeichenfolgen und Zahlen den Zeichenfolgentyp zum Vergleich in eine Zahl umwandelt. Wenn der Feldtyp eine Zeichenfolge ist, wird dem Feld daher eine Funktion hinzugefügt, was dazu führt, dass der Index fehlschlägt.

In der offiziellen Dokumentation wird erklärt : Zeichenfolgen werden bei Bedarf automatisch in Zahlen und Zahlen in Zeichenfolgen umgewandelt.

-- 字段类型为varchar,传参为整数,无法走到索引
mysql> explain select * from t1 where a=1000;
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | a             | NULL | NULL    | NULL | 498892 |    10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 3 warnings (0.00 sec)
mysql> show warnings;
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                           |
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1739 | Cannot use ref access on index 'a' due to type or collation conversion on field 'a'                                                               |
| Warning | 1739 | Cannot use range access on index 'a' due to type or collation conversion on field 'a'                                                             |
| Note    | 1003 | /* select#1 */ select `test1`.`t1`.`id` AS `id`,`test1`.`t1`.`a` AS `a`,`test1`.`t1`.`b` AS `b` from `test1`.`t1` where (`test1`.`t1`.`a` = 1000) |
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)
-- 字段类型为int,传参为字符串,可以走到索引
mysql> explain select * from t2 where a='1000';
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t2    | NULL       | ref  | a             | a    | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

Warum können Sie Zahlen zum Vergleich nicht in Zeichenfolgen umwandeln?

Vergleichsergebnisse unten:

  • Beim Vergleich von Zeichenfolgen wird die Größe der Zeichenfolge einzeln verglichen, bis unterschiedliche Zeichen gefunden werden. Die Vergleichsergebnisse dieses Vergleichs unterscheiden sich von den Vergleichsergebnissen von Zahlen.
mysql> select '2000' <'250';
+---------------+
| '2000' <'250' |
+---------------+
|             1 |
+---------------+
1 row in set (0.00 sec)

Datentypkonvertierung in Tabellenverknüpfungen

Wenn die Verbindungsfeldtypen der beiden Tabellen inkonsistent sind, führt dies zu einer impliziten Konvertierung (eine interne MySQL- cast()Funktion wird hinzugefügt), der Verbindungsfeldindex kann nicht erreicht werden und die optimale Tabellenverbindungsreihenfolge wird möglicherweise nicht verwendet.

Die Tabelle, die ursprünglich eine getriebene Tabelle war, kann als treibende Tabelle verwendet werden, da der Index nicht verwendet werden kann.

Beispiel:

  • Unter normalen Umständen t2wird die Tabelle wie folgt als treibende Tabelle ausgewählt. Aufgrund unterschiedlicher Datentypen lautet die tatsächliche SQL-Ausführung jedoch wie folgt:select * from t1 join t2 on cast(t1.a as unsigned)=t2.a where t2.id<1000
  • Bei t1Verwendung als gesteuerte Tabelle gibt es keine Möglichkeit, zum t1.aIndex von zu wechseln, daher t1wird die Tabelle als steuernde Tabelle ausgewählt
mysql> explain select * from t1 join t2 on t1.a=t2.a where t2.id<1000;
+----+-------------+-------+------------+------+---------------+------+---------+------------+--------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref        | rows   | filtered | Extra                 |
+----+-------------+-------+------------+------+---------------+------+---------+------------+--------+----------+-----------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | a             | NULL | NULL    | NULL       | 498892 |   100.00 | Using where           |
|  1 | SIMPLE      | t2    | NULL       | ref  | PRIMARY,a     | a    | 5       | test1.t1.a |      1 |     5.00 | Using index condition |
+----+-------------+-------+------------+------+---------------+------+---------+------------+--------+----------+-----------------------+
2 rows in set, 2 warnings (0.00 sec)
mysql> show warnings;
+---------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                                                                    |
+---------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1739 | Cannot use ref access on index 'a' due to type or collation conversion on field 'a'                                                                                                                                                                                                        |
| Note    | 1003 | /* select#1 */ select `test1`.`t1`.`id` AS `id`,`test1`.`t1`.`a` AS `a`,`test1`.`t1`.`b` AS `b`,`test1`.`t2`.`id` AS `id`,`test1`.`t2`.`a` AS `a`,`test1`.`t2`.`b` AS `b` from `test1`.`t1` join `test1`.`t2` where ((`test1`.`t2`.`id` < 1000) and (`test1`.`t1`.`a` = `test1`.`t2`.`a`)) |
+---------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.01 sec)

Implizite Konvertierung von Zeichensätzen

Wenn der Parameterzeichensatz und der Feldzeichensatz unterschiedlich sind, kann kein direkter Vergleich durchgeführt werden und es ist eine Zeichensatzkonvertierung erforderlich. Möglicherweise müssen Sie convert()dem Konvertierungsfeld eine Funktion hinzufügen, um den Zeichensatz zu konvertieren, was zu einem Indexfehler führt.

Testtabellenstruktur

  • Der Datenbankzeichensatz ist UTF8MB4
  • t1Der Tabellenzeichensatz ist UTF8
  • t2Der Tabellenzeichensatz ist UTF8MB4
mysql> show create database test\G
*************************** 1. row ***************************
       Database: test
Create Database: CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET utf8mb4 */
mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) NOT NULL,
  `a` varchar(20) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> show create table t2\G
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `id` int(11) NOT NULL,
  `a` varchar(20) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.01 sec)

Beispiel für eine einzelne Tabelle

-- 正常执行时,匹配字段的字符集(没有单独指定时继承表的字符集)
mysql> explain select * from t1 where a='1000';
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t1    | NULL       | ref  | a             | a    | 63      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

-- 将参数转换不同的字符集,无法走到索引,而是全表扫描
mysql> explain select * from t1 where a=convert('1000' using utf8mb4);
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 2000 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)


-- show warnings可以看到优化器进行了转换,在t1.a上加了convert函数,从而无法走到索引
mysql> show warnings;
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                               |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (convert(`test`.`t1`.`a` using utf8mb4) = <cache>(convert('1000' using utf8mb4))) |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Darüber hinaus ist zu beachten:

MySQL räumt intern der Konvertierung von Zeichensätzen niedriger Ebene in Zeichensätze höherer Ebene Priorität ein, beispielsweise der Konvertierung von UTF8 in UTF8MB4.

Im vorherigen Beispiel convert()wurde die Funktion t1.azu hinzugefügt, im folgenden Beispiel convert()wurde die Funktion jedoch zum Parameter anstelle t2.ades Felds hinzugefügt. Diese Situation führte nicht zu einer schlechten Leistung:

mysql> show create table t2\G
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `id` int(11) NOT NULL,
  `a` varchar(20) DEFAULT NULL,
  `b` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
mysql> explain select * from t2 where a=convert('1000' using utf8);
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t2    | NULL       | ref  | a             | a    | 83      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings;
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                   |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `test`.`t2`.`id` AS `id`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` = convert(convert('1000' using utf8) using utf8mb4)) |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Um zusammenzufassen:

  • Wenn der Zeichensatz des Tabellenfelds ein Zeichensatz niedrigerer Ebene (z. B. UTF8) ist und der eingehende Wert ein Zeichensatz höherer Ebene (z. B. UTF8MB4) ist, wird der Zeichensatz des Tabellenfelds zu diesem Zeitpunkt konvertiert. Dies entspricht der Verwendung der Funktion, Index ungültig.
  • Wenn das Tabellenfeld ein Zeichensatz höherer Ebene (z. B. UTF8MB4) und der eingehende Wert ein Zeichensatz niedrigerer Ebene (z. B. UTF8) ist, wird der eingehende Wert in den Zeichensatz konvertiert und verursacht keinen Indexfehler. .

Normalerweise verwenden wir convert()die Funktion jedoch nicht zum manuellen Konvertieren des Zeichensatzes von Parametern. In den folgenden beiden Szenarien kann es zu impliziten Typkonvertierungen kommen, die leicht zu ignorieren sind und zu Produktionsproblemen führen.

Zeichensatzkonvertierung in Tabellenverknüpfungen

Wenn die Zeichensätze der Verbindungsfelder der beiden Tabellen inkonsistent sind, führt dies zu einer impliziten Konvertierung ( convert()in MySQL hinzugefügte Funktion), und der Verbindungsfeldindex kann nicht erreicht werden und die optimale Tabellenverbindungssequenz wird möglicherweise nicht verwendet.

Die Tabelle, die ursprünglich eine getriebene Tabelle war, kann als treibende Tabelle verwendet werden, da der Index nicht verwendet werden kann.

Beispiel:

  • Unter normalen Umständen gibt MySQL Tabellen mit kleinen Ergebnismengen als treibende Tabellen den Vorrang. In diesem Beispiel handelt es sich um t2die treibende Tabelle und t1die getriebene Tabelle.
  • Aufgrund der unterschiedlichen Zeichensätze ist das tatsächlich ausgeführte SQL jedoch wie in der Abbildung show warningsdargestellt . Wenn t1.adem Feld eine Funktion convert()zum Konvertieren des Zeichensatzes hinzugefügt wird, t1.akann der Index des Feldes nicht erreicht werden und die Verbindungsreihenfolge muss geändert werden .
mysql> explain select * from t1 left join t2 on t1.a=t2.a where t2.id<1000;
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra                 |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 498649 |   100.00 | NULL                  |
|  1 | SIMPLE      | t2    | NULL       | ref  | PRIMARY,a     | a    | 83      | func |      1 |     4.79 | Using index condition |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------+
2 rows in set, 1 warning (0.00 sec)
mysql> show warnings;
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                                |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`id` AS `id`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`id` < 1000) and (convert(`test`.`t1`.`a` using utf8mb4) = `test`.`t2`.`a`)) |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)




-- 在下面示例中,虽然也发生了类型转换,但是效率并没有变差,因为原本最优的连接顺序就是t1作为驱动表
mysql> explain select * from t1 left join t2 on t1.a=t2.a where t1.id<1000;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |  999 |   100.00 | Using where |
|  1 | SIMPLE      | t2    | NULL       | ref   | a             | a       | 83      | func |    1 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)


mysql> show warnings;
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                                   |
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`id` AS `id`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` left join `test`.`t2` on((convert(`test`.`t1`.`a` using utf8mb4) = `test`.`t2`.`a`)) where (`test`.`t1`.`id` < 1000) |
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Zeichensatzkonvertierung in gespeicherten Prozeduren

Dies ist auch ein Szenario, das relativ leicht zu ignorieren ist. Das Problem wurde entdeckt, als der Primärschlüssel während des Speichervorgangs in der Produktionsumgebung aktualisiert wurde, die Ausführung jedoch mehr als 10 Sekunden dauerte.

Der Zeichensatz der Variablen in der gespeicherten Prozedur wird vom databaseZeichensatz von (kann auch beim Erstellen angegeben werden) verwendet. Wenn sich der Zeichensatz des Tabellenfelds databasevom Zeichensatz von () unterscheidet, erfolgt eine implizite Zeichensatztypkonvertierung ähnlich der vorherigen einer wird passieren.

Beispiel:

  • databaseDer Zeichensatz ist UTF8MB4
  • character_set_clientund sind die Werte der Sitzung und collation_connectionbeim Erstellen der gespeicherten Prozedurcharacter_set_clientcollation_connection
  • Es wurde getestet, dass der Zeichensatz der Variablen in der gespeicherten Prozedur mit dem Zeichensatz auf Datenbankebene übereinstimmt.
-- 存储过程信息: Database Collation: utf8mb4_general_ci
mysql> show create procedure update_data\G
*************************** 1. row ***************************
           Procedure: update_data
            sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
    Create Procedure: CREATE DEFINER=`root`@`%` PROCEDURE `update_data`()
begin
  declare j int;
  declare n varchar(100);
   select charset(n);
  set j=1;
  while(j<=2000)do
set n = cast(j as char);
select 1,now();
    update t1 set b=concat(b,'1') where a=n;
select 2,now();
select sleep(1);
    set j=j+1;
  end while;
end
character_set_client: utf8mb4
collation_connection: utf8mb4_general_ci
  Database Collation: utf8mb4_general_ci
1 row in set (0.00 sec)
如下,在执行存储过程后,看到打印的变量n的字符集是utf8mb4


mysql> call update_data();
+------------+
| charset(n) |
+------------+
| utf8mb4    |
+------------+
1 row in set (0.00 sec)

Die auf der Grundlage des Indexfelds aktualisierte Anweisung asieht unter Verwendung eines vollständigen Tabellenscans (Typ: Index, Schlüssel: Primär) tatsächlich wie folgt aus.

mysql> explain update t1 set b=concat(b,'1') where a=convert('1000' using utf8mb4);
+----+-------------+-------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
|  1 | UPDATE      | t1    | NULL       | index | NULL          | PRIMARY | 4       | NULL | 498649 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+--------+----------+-------------+
1 row in set (0.00 sec)


-- 而正常情况下,执行计划为:
mysql> explain update t1 set b=concat(b,'1') where a='1000';
+----+-------------+-------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
|  1 | UPDATE      | t1    | NULL       | range | a             | a    | 63      | const |    1 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
1 row in set (0.00 sec)

Die Aktualisierungszeit wurde ebenfalls von 0,00 Sek. auf 0,60 Sek. geändert . Wenn die Menge an Tabellendaten groß ist, hat ein vollständiger Tabellenscan größere Auswirkungen auf die Produktion.

mysql> update t1 set b=concat(b,'1') where a='1000';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> update t1 set b=concat(b,'1') where a=convert('1000' using utf8mb4);
Query OK, 1 row affected (0.60 sec)
Rows matched: 1  Changed: 1  Warnings: 0

So vermeiden Sie implizite Konvertierungen

Für die implizite Konvertierung von Datentypen:

  1. Auswahl des Standarddatentyps
  2. SQL-Übergabe der Datentypübereinstimmung der beteiligten Felder

Bei der impliziten Konvertierung von Zeichensätzen bleiben Client-Zeichensatz, serverseitiger Zeichensatz, Datenbank-Zeichensatz, Tabellen-Zeichensatz und Feld-Zeichensatz konsistent.

Weitere technische Artikel finden Sie unter: https://opensource.actionsky.com/

Über SQLE

SQLE ist eine umfassende SQL-Qualitätsmanagementplattform, die die SQL-Prüfung und -Verwaltung von der Entwicklung bis zur Produktionsumgebung abdeckt. Es unterstützt gängige Open-Source-, kommerzielle und inländische Datenbanken, bietet Prozessautomatisierungsfunktionen für Entwicklung, Betrieb und Wartung, verbessert die Online-Effizienz und verbessert die Datenqualität.

SQLE erhalten

Typ Adresse
Repository https://github.com/actiontech/sqle
dokumentieren https://actiontech.github.io/sqle-docs/
Neuigkeiten veröffentlichen https://github.com/actiontech/sqle/releases
Entwicklungsdokumentation für das Datenaudit-Plug-in https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
Die Raubkopien von „Qing Yu Nian 2“ wurden auf npmror hochgeladen, was dazu führte, dass npmmirror den Unpkg-Dienst einstellen musste: Es bleibt nicht mehr viel Zeit für Google. Ich schlage vor, dass alle Produkte Open Source sind . time.sleep(6) spielt hier eine Rolle. Linus ist am aktivsten beim „Hundefutter fressen“! Das neue iPad Pro verwendet 12 GB Speicherchips, behauptet jedoch, über 8 GB Speicher zu verfügen. People’s Daily Online bewertet die Aufladung im Matroschka-Stil: Nur durch aktives Lösen des „Sets“ können wir eine Zukunft haben Neues Entwicklungsparadigma für Vue3, ohne die Notwendigkeit von „ref/reactive“ und ohne die Notwendigkeit von „ref.value“. MySQL 8.4 LTS Chinesisches Handbuch veröffentlicht: Hilft Ihnen, den neuen Bereich der Datenbankverwaltung zu meistern Tongyi Qianwen GPT-4-Level-Hauptmodellpreis reduziert um 97 %, 1 Yuan und 2 Millionen Token
{{o.name}}
{{m.name}}

Ich denke du magst

Origin my.oschina.net/actiontechoss/blog/11183928
Empfohlen
Rangfolge