MySQL 암시적 변환을 알고 이해해야 합니다.

프로덕션 환경에는 SQL 인덱스의 실패와 성능 저하를 유발하는 암시적 유형 변환이 종종 있으며, 이는 결국 클러스터 로드와 비즈니스에 영향을 미칩니다. 이 문서에는 암시적 변환의 일반적인 시나리오가 요약되어 있습니다. 프로덕션에서는 SQL 암시적 변환을 피하십시오.

저자: Zhang Luodan은 데이터베이스 기술에 열정을 갖고 있으며, 앞으로도 더 깊이 있는 기사를 작성하고 더 가치 있는 콘텐츠를 생산하기를 희망합니다.

Aikeson 오픈 소스 커뮤니티에서 제작되었습니다. 원본 콘텐츠는 승인 없이 사용할 수 없습니다. 편집자에게 연락하여 재인쇄할 출처를 명시해 주세요.

이 글은 3,000단어 정도이며 읽는 데 10분 정도 걸릴 것으로 예상됩니다.

SQL이 암시적 변환을 생성하는 일반적인 시나리오는 다음과 같습니다.

  1. 데이터 유형의 암시적 변환
  2. 문자 세트의 암시적 변환

그중에서도 특히 테이블 연결 시나리오 및 저장 프로시저에서 문자 집합 변환은 쉽게 간과됩니다.

참고: 문자 세트는 문자 유형 데이터의 인코딩 규칙입니다. 숫자 유형의 경우 문자 세트를 변환할 필요가 없습니다.

데이터 유형의 암시적 변환

테스트 테이블 구조

t1테이블 필드 a는 VARCHAR 유형이고 t2테이블 필드 a는 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)

단일 테이블 예

여기서 주목해야 할 점은 다음과 같은 두 가지 유형의 변환이 있다는 것입니다.

  1. 필드 유형이 문자열 유형이고 매개변수가 정수인 경우 인덱스가 실패합니다.
  2. 필드 유형이 정수이고 수신 매개변수가 문자열 유형인 경우 인덱스가 실패하지 않습니다.

이는 문자열을 숫자와 비교할 때 MySQL이 비교를 위해 문자열 유형을 숫자로 변환하므로, 필드 유형이 문자열인 경우 해당 필드에 함수가 추가되어 인덱스가 실패하게 되기 때문입니다.

공식 문서에서는 다음과 같이 설명합니다 . 문자열은 필요에 따라 자동으로 숫자로 변환되고 숫자는 문자열로 변환됩니다.

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

비교를 위해 숫자를 문자열로 변환할 수 없는 이유는 무엇입니까?

아래 비교 결과:

  • 문자열 비교는 다른 문자를 찾을 때까지 문자열의 크기를 하나씩 비교하는 것입니다. 이 비교의 비교 결과는 숫자의 비교 결과와 다릅니다.
mysql> select '2000' <'250';
+---------------+
| '2000' <'250' |
+---------------+
|             1 |
+---------------+
1 row in set (0.00 sec)

테이블 조인의 데이터 유형 변환

두 테이블의 연결 필드 유형이 일치하지 않으면 암시적 변환(MySQL 내부 cast()함수 추가)이 발생하여 연결 필드 인덱스에 도달할 수 없으며 최적의 테이블 연결 순서를 사용하지 못할 수 있습니다.

원래 구동 테이블이었던 테이블은 인덱스를 사용할 수 없기 때문에 구동 테이블로 사용할 수 있습니다.

예:

  • 다음과 같이 일반적인 상황에서는 t2테이블이 구동 테이블로 선택되지만 데이터 유형이 다르기 때문에 실제 실행되는 SQL은 다음과 같습니다.select * from t1 join t2 on cast(t1.a as unsigned)=t2.a where t2.id<1000
  • 피동 테이블로 사용하는 경우 의 인덱스 t1로 갈 수 없으므로 해당 테이블을 구동 테이블로 선택합니다.t1.at1
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)

문자 세트의 암시적 변환

매개변수 문자셋과 필드 문자셋이 다를 경우 직접 비교가 불가능하며, 문자셋 convert()변환을 위해 변환 필드에 함수를 추가해야 하므로 인덱스 실패가 발생할 수 있습니다.

테스트 테이블 구조

  • 데이터베이스 문자 집합은 UTF8MB4입니다.
  • t1테이블 문자 집합은 UTF8입니다.
  • t2테이블 문자 집합은 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)

단일 테이블 예

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

또한 다음 사항에 유의해야 합니다.

MySQL은 내부적으로 UTF8을 UTF8MB4로 변환하는 것과 같이 낮은 수준의 문자 집합을 더 높은 수준의 문자 집합으로 변환하는 데 우선 순위를 부여합니다.

이전 예에서는 convert()함수가 t1.a에 추가되었지만 다음 예에서는 필드 convert()대신 매개변수에 함수가 추가되었으므로 t2.a성능이 저하되지 않았습니다.

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)

요약하자면:

  • 테이블 필드 문자 세트가 하위 문자 세트(예: UTF8)이고 수신 값이 상위 레벨 문자 세트(예: UTF8MB4)인 경우, 이때 테이블 필드의 문자 세트가 변환됩니다. 이는 함수를 사용하는 것과 같습니다. 인덱스가 잘못되었습니다.
  • 테이블 필드가 상위 수준 문자 집합(예: UTF8MB4)이고 들어오는 값이 하위 수준 문자 집합(예: UTF8)인 경우 들어오는 값은 문자 집합으로 변환되므로 인덱스 오류가 발생하지 않습니다. .

그러나 우리는 일반적으로 매개변수의 문자 집합을 수동으로 변환하는 함수를 사용하지 않습니다 convert(). 다음 두 시나리오에서는 무시하기 쉬운 암시적 유형 변환이 있을 수 있으며 이로 인해 생산 문제가 발생합니다.

테이블 조인의 문자 집합 변환

두 테이블의 연결 필드의 문자 집합이 일치하지 않으면 암시적 변환( convert()MySQL 내부에 함수 추가)이 발생하고 연결 필드 인덱스에 도달할 수 없으며 최적의 테이블 연결 순서가 사용되지 않을 수 있습니다.

원래 구동 테이블이었던 테이블은 인덱스를 사용할 수 없기 때문에 구동 테이블로 사용할 수 있습니다.

예:

  • 일반적인 상황에서 MySQL은 작은 결과 집합이 있는 테이블을 구동 테이블로 우선순위로 지정합니다. 이 예에서는 t2구동 테이블과 t1구동 테이블입니다.
  • 그러나 문자 집합이 다르기 때문에 실제로 실행되는 SQL은 그림과 같습니다 show warnings. 문자 집합을 변환하는 함수를 t1.a필드에 추가 하면 해당 필드의 인덱스에 도달할 수 없으며 연결 순서를 변경해야 합니다. .convert()t1.a
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)

저장 프로시저의 문자 세트 변환

이는 비교적 무시하기 쉬운 시나리오이기도 합니다. 프로덕션 환경에서 저장 프로세스 중에 기본 키가 업데이트되었을 때 문제가 발견되었지만 실행하는 데 10초 이상이 걸렸습니다.

저장 프로시저의 변수 문자 세트는 database(생성 시 지정 가능)의 문자 세트에서 상속됩니다. 테이블 필드 문자 세트가 database()의 문자 세트와 다른 경우 암시적 문자 세트 유형 변환은 이전과 유사합니다. 하나가 발생합니다.

예:

  • database문자 집합은 UTF8MB4입니다.
  • character_set_client세션의 값 이며 collation_connection저장 프로시저를 생성할 때의 값입니다 character_set_client.collation_connection
  • 저장 프로시저의 변수 문자 집합이 데이터베이스 수준의 문자 집합과 일치하는지 테스트되었습니다.
-- 存储过程信息: 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)

인덱스 필드를 기반으로 업데이트된 명령문은 a전체 테이블 스캔(유형: 인덱스, 키: 기본)을 사용하여 실제로 다음과 같습니다.

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)

업데이트 시간도 0.00초 에서 0.60초로 변경되었습니다 . 테이블 데이터의 양이 많을 경우 전체 테이블 스캔이 프로덕션에 더 큰 영향을 미칩니다.

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

암시적 변환을 피하는 방법

데이터 유형의 암시적 변환의 경우:

  1. 표준 데이터 유형 선택
  2. SQL 패스 참여 필드 데이터 유형 일치

문자 집합의 암시적 변환의 경우: 클라이언트 문자 집합, 서버측 문자 집합, 데이터베이스 문자 집합, 테이블 문자 집합 및 필드 문자 집합이 일관성을 유지합니다.

더 많은 기술 기사를 보려면 https://opensource.actionsky.com/을 방문하세요.

SQLE 소개

SQLE는 개발부터 프로덕션 환경까지 SQL 감사 및 관리를 포괄하는 포괄적인 SQL 품질 관리 플랫폼입니다. 주류 오픈소스, 상용 및 국내 데이터베이스를 지원하고 개발, 운영 및 유지 관리를 위한 프로세스 자동화 기능을 제공하고 온라인 효율성을 향상시키며 데이터 품질을 향상시킵니다.

SQLE 가져오기

유형 주소
저장소 https://github.com/actiontech/sqle
문서 https://actiontech.github.io/sqle-docs/
출시 소식 https://github.com/actiontech/sqle/releases
데이터 감사 플러그인 개발 문서 https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
"Qing Yu Nian 2"의 불법 복제된 리소스가 npm에 업로드되어 npmmirror가 unpkg 서비스를 중단하게 되었습니다. Zhou Hongyi: Google에 남은 시간이 많지 않습니다. time.sleep(6) 여기서는 어떤 역할을 합니까? 리누스는 "개사료 먹기"에 가장 적극적입니다! 새로운 iPad Pro는 12GB의 메모리 칩을 사용하지만 8GB의 메모리를 가지고 있다고 주장합니다. People's Daily Online은 사무용 소프트웨어의 마트료시카 스타일 충전을 검토합니다. "세트"를 적극적으로 해결해야만 Flutter 3.22 및 Dart 3.4 출시가 가능 합니다. 'ref/reactive'가 필요 없는 Vue3의 새로운 개발 패러다임, 'ref.value'가 필요 없음 MySQL 8.4 LTS 중국어 매뉴얼 출시: 데이터베이스 관리의 새로운 영역을 마스터하는 데 도움 Tongyi Qianwen GPT-4 수준 메인 모델 가격 인하 97% 증가, 1위안 200만 토큰
{{o.이름}}
{{이름}}

추천

출처my.oschina.net/actiontechoss/blog/11183928