La conversion implicite MySQL doit être connue et comprise

Dans l'environnement de production, certaines conversions de type implicites entraînent souvent l'échec et les performances extrêmement médiocres des index SQL, ce qui affecte à son tour la charge et l'activité du cluster. Cet article résume les scénarios courants de conversion implicite. Essayez d’éviter la conversion implicite SQL en production.

Auteur : Zhang Luodan est passionné par la technologie des bases de données et explore constamment. Il espère écrire des articles plus approfondis et produire un contenu plus précieux à l'avenir !

Produit par la communauté open source Aikeson. Le contenu original ne peut être utilisé sans autorisation. Veuillez contacter l'éditeur et indiquer la source pour la réimpression.

Cet article compte environ 3 000 mots et sa lecture devrait prendre 10 minutes.

Les scénarios courants dans lesquels SQL génère des conversions implicites incluent :

  1. Conversion implicite des types de données
  2. Conversion implicite des jeux de caractères

Parmi eux, la conversion des jeux de caractères, en particulier dans les scénarios de connexion de tables et les procédures stockées, est facilement négligée.

Remarque : Le jeu de caractères est la règle de codage pour les données de type caractère. Pour les types numériques, il n'est pas nécessaire de convertir le jeu de caractères.

Conversion implicite des types de données

Structure de la table de test

t1Les champs de la table asont de type VARCHAR et t2les champs de la table asont de type 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)

Exemple de table unique

Ce qu’il faut noter ici, c’est qu’il existe les deux types de conversions suivants :

  1. Lorsque le type de champ est un type chaîne et que le paramètre est un entier, l'index échoue.
  2. Lorsque le type de champ est un entier et que le paramètre entrant est un type de chaîne, cela n’entraînera pas l’échec de l’index.

En effet, lors de la comparaison de chaînes avec des nombres, MySQL convertira le type de chaîne en nombre à des fins de comparaison. Par conséquent, lorsque le type de champ est une chaîne, une fonction sera ajoutée au champ, provoquant l'échec de l'index.

La documentation officielle explique : Les chaînes sont automatiquement converties en nombres et les nombres en chaînes si nécessaire.

-- 字段类型为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)

Quant à savoir pourquoi vous ne pouvez pas convertir de nombres en chaînes à des fins de comparaison ?

Résultats de comparaison ci-dessous :

  • La comparaison des chaînes consiste à comparer la taille des chaînes une par une jusqu'à ce que différents caractères soient trouvés. Les résultats de cette comparaison sont différents des résultats de la comparaison des nombres.
mysql> select '2000' <'250';
+---------------+
| '2000' <'250' |
+---------------+
|             1 |
+---------------+
1 row in set (0.00 sec)

Conversion de type de données dans les jointures de tables

Lorsque les types de champs de connexion des deux tables sont incohérents, cela entraînera une conversion implicite ( cast()une fonction interne MySQL est ajoutée), et l'index du champ de connexion ne peut pas être atteint et l'ordre optimal de connexion de la table peut ne pas être utilisé.

La table qui était à l'origine une table pilotée peut être utilisée comme table pilotante car l'index ne peut pas être utilisé.

Exemple:

  • Comme suit, dans des circonstances normales, t2la table sera sélectionnée comme table de pilotage, mais en raison des différents types de données, le SQL réellement exécuté est :select * from t1 join t2 on cast(t1.a as unsigned)=t2.a where t2.id<1000
  • Si t1elle est utilisée comme table pilotée, il n'y a aucun moyen d'accéder à t1.al'index de , donc t1la table est sélectionnée comme table pilote
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)

Conversion implicite des jeux de caractères

Lorsque le jeu de caractères du paramètre et le jeu de caractères du champ sont différents, une comparaison directe ne peut pas être effectuée et une conversion du jeu de caractères est requise. Vous devrez peut-être ajouter convert()une fonction au champ de conversion pour convertir le jeu de caractères, ce qui entraînera un échec de l'index.

Structure de la table de test

  • Le jeu de caractères de la base de données est UTF8MB4
  • t1Le jeu de caractères du tableau est UTF8
  • t2Le jeu de caractères du tableau est 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)

Exemple de table unique

-- 正常执行时,匹配字段的字符集(没有单独指定时继承表的字符集)
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)

De plus, il convient de noter que :

MySQL donnera en interne la priorité à la conversion des jeux de caractères de bas niveau en jeux de caractères de niveau supérieur, comme la conversion d'UTF8 en UTF8MB4.

Dans l'exemple précédent, convert()la fonction a été ajoutée t1.aà , mais dans l'exemple suivant, convert()la fonction a été ajoutée au paramètre au lieu du t2.achamp. Cette situation n'a pas entraîné de mauvaises performances :

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)

Pour résumer:

  • Lorsque le jeu de caractères du champ de table est un jeu de caractères de niveau inférieur (tel que UTF8) et que la valeur entrante est un jeu de caractères de niveau supérieur (tel que UTF8MB4), le jeu de caractères du champ de table sera converti à ce moment-là, ce qui équivaut à utiliser la fonction Function, index invalide.
  • Lorsque le champ de la table est un jeu de caractères de niveau supérieur (tel que UTF8MB4) et que la valeur entrante est un jeu de caractères de niveau inférieur (tel que UTF8), la valeur entrante sera convertie en jeu de caractères et n'entraînera pas d'échec de l'index. .

Cependant, nous n'utilisons généralement pas convert()la fonction pour convertir manuellement le jeu de caractères des paramètres. Dans les deux scénarios suivants, il peut y avoir des conversions de type implicites faciles à ignorer, provoquant des problèmes de production.

Conversion du jeu de caractères dans les jointures de tables

Lorsque les jeux de caractères des champs de connexion des deux tables sont incohérents, cela entraînera une conversion implicite ( convert()fonction ajoutée dans MySQL), et l'index du champ de connexion ne pourra pas être atteint et la séquence de connexion de table optimale ne pourra pas être utilisée.

La table qui était à l'origine une table pilotée peut être utilisée comme table pilotante car l'index ne peut pas être utilisé.

Exemple:

  • Dans des circonstances normales, MySQL donnera la priorité aux tables avec de petits ensembles de résultats comme tables pilotes. Dans cet exemple, il s'agit t2de la table pilote et t1de la table pilotée.
  • Cependant, en raison des différents jeux de caractères, le SQL réellement exécuté est tel show warningsqu'indiqué sur la figure. Si une fonction t1.aest ajoutée au champ convert()pour convertir le jeu de caractères, t1.al'index du champ ne peut pas être atteint et l'ordre de connexion doit être modifié. .
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)

Conversion de jeux de caractères dans les procédures stockées

Il s'agit également d'un scénario relativement facile à ignorer. Le problème a été découvert lors de la mise à jour de la clé primaire pendant le processus de stockage dans l'environnement de production, mais son exécution a pris plus de 10 s.

Le jeu de caractères des variables dans la procédure stockée est hérité du databasejeu de caractères de (peut également être spécifié lors de la création). Lorsque le jeu de caractères du champ de table databaseest différent du jeu de caractères de (), conversion implicite du type de jeu de caractères similaire à la précédente. il y en aura un.

Exemple:

  • databaseLe jeu de caractères est UTF8MB4
  • character_set_clientet sont les valeurs de session et collation_connectionlors de la création de la procédure stockéecharacter_set_clientcollation_connection
  • Il a été testé que le jeu de caractères des variables dans la procédure stockée est cohérent avec le jeu de caractères au niveau de la base de données.
-- 存储过程信息: 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)

L'instruction mise à jour en fonction du champ d'index adevient en réalité la suivante, en utilisant une analyse complète de la table (type : index, clé : primaire).

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)

Le temps de mise à jour est également passé de 0,00 s à 0,60 s . Lorsque la quantité de données de table est importante, une analyse complète de la table aura un plus grand impact sur la production.

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

Comment éviter les conversions implicites

Pour la conversion implicite des types de données :

  1. Sélection du type de données standard
  2. Correspondance du type de données du champ participant de passe SQL

Pour la conversion implicite des jeux de caractères : le jeu de caractères client, le jeu de caractères côté serveur, le jeu de caractères de base de données, le jeu de caractères de table et le jeu de caractères de champ restent cohérents.

Pour des articles plus techniques, veuillez visiter : https://opensource.actionsky.com/

À propos de SQLE

SQLE est une plateforme complète de gestion de la qualité SQL qui couvre l'audit et la gestion SQL, du développement aux environnements de production. Il prend en charge les bases de données open source, commerciales et nationales grand public, fournit des capacités d'automatisation des processus pour le développement, l'exploitation et la maintenance, améliore l'efficacité en ligne et améliore la qualité des données.

SQLE obtenir

taper adresse
Dépôt https://github.com/actiontech/sqle
document https://actiontech.github.io/sqle-docs/
publier des nouvelles https://github.com/actiontech/sqle/releases
Documentation de développement du plug-in d'audit des données https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
Les ressources piratées de "Qing Yu Nian 2" ont été téléchargées sur npm, obligeant npmmirror à suspendre le service unpkg. Zhou Hongyi : Il ne reste plus beaucoup de temps à Google. Je suggère que tous les produits soient open source. time.sleep(6) joue ici un rôle. Linus est le plus actif dans la « consommation de nourriture pour chiens » ! Le nouvel iPad Pro utilise 12 Go de puces mémoire, mais prétend disposer de 8 Go de mémoire. Le People's Daily Online examine la charge de type matriochka des logiciels de bureau : Ce n'est qu'en résolvant activement « l'ensemble » que nous pourrons avoir un avenir avec Flutter 3.22 et Dart 3.4 . nouveau paradigme de développement pour Vue3, sans avoir besoin de « ref/reactive », pas besoin de « ref.value » Publication du manuel chinois MySQL 8.4 LTS : vous aider à maîtriser le nouveau domaine de la gestion de bases de données Tongyi Qianwen niveau GPT-4 prix du modèle principal réduit de 97%, 1 yuan et 2 millions de jetons
{{o.name}}
{{m.nom}}

Je suppose que tu aimes

Origine my.oschina.net/actiontechoss/blog/11183928
conseillé
Classement