MySQL无需更改结构即可转换为UTF8

时间:2016-05-20 22:22:18

标签: mysql utf-8 replication

我有一个相当大的数据库,我正在尝试将字符集和排序规则latin1/latin1_swedish_ci转换为utf8mb4/utf8mb4_unicode_ci。我希望设置复制到从站,运行转换,然后在完成时提升从站,以避免停机。

我注意到在运行查询时...

ALTER TABLE `sometable` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

... MySQL自动将text转换为mediumtextmediumtext转换为longtext等。

有没有办法关闭此功能? MySQL有这个功能很好,但问题是它打破了复制,因为从机上的表结构与主机不同。

2 个答案:

答案 0 :(得分:4)

正如ALTER TABLE Syntax所述:

  

对于数据类型为VARCHAR或其中一种TEXT类型的列,CONVERT TO CHARACTER SET会根据需要更改数据类型,以确保新列的长度足以支持存储与原始列一样多的字符。例如,TEXT列有两个长度字节,用于存储列中值的字节长度,最大值为65,535。对于latin1 TEXT列,每个字符都需要一个字节,因此该列最多可以存储65,535个字符。如果列转换为utf8,则每个字符最多可能需要三个字节,最大可能长度为3×65,535 = 196,605字节。该长度不适合TEXT列的长度字节,因此MySQL将数据类型转换为MEDIUMTEXT,这是长度字节可以记录值196,605的最小字符串类型。同样,VARCHAR列可能会转换为MEDIUMTEXT

     

为避免更改上述类型的数据类型,请勿使用CONVERT TO CHARACTER SET。而是使用MODIFY更改单个列。例如:

ALTER TABLE t MODIFY latin1_text_col TEXT CHARACTER SET utf8;
ALTER TABLE t MODIFY latin1_varchar_col VARCHAR(M) CHARACTER SET utf8;

答案 1 :(得分:0)

(不是一个真正的答案,而是一些说明性的例子。)

案例1:文本在latin1列中正确存储为latin1;使用CONVERT TO

mysql>     CREATE TABLE alters (
    ->         c VARCHAR(11)  CHARACTER SET latin1  NOT NULL
    ->     );

mysql>     INSERT INTO alters (c) VALUES ('aabc'), (UNHEX('61e06263')), (UNHEX('61e16263'));

mysql>     SELECT c, HEX(c) from alters;
+-------+----------+
| c     | HEX(c)   |
+-------+----------+
| aabc  | 61616263 |
| aàbc  | 61E06263 |
| aábc  | 61E16263 |
+-------+----------+

mysql>     ALTER TABLE alters CONVERT TO CHARACTER SET utf8;

mysql>     SELECT c, HEX(c) from alters;
+-------+------------+
| c     | HEX(c)     |
+-------+------------+
| aabc  | 61616263   |
| aàbc  | 61C3A06263 |
| aábc  | 61C3A16263 |
+-------+------------+

mysql>     -- Observation: text was correctly converted to utf8.

mysql>     SHOW CREATE TABLE alters\G
Create Table: CREATE TABLE `alters` (
  `c` varchar(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

案例2:文本在latin1列中正确存储为latin1;使用" Double ALTER"

mysql>     CREATE TABLE alters (
    ->         c VARCHAR(11)  CHARACTER SET latin1  NOT NULL
    ->     );

mysql>     INSERT INTO alters (c) VALUES ('aabc'), (UNHEX('61e06263')), (UNHEX('61e16263'));

mysql>     ALTER TABLE alters MODIFY  c VARBINARY(11) NOT NULL;

mysql>     ALTER TABLE alters MODIFY  c VARCHAR(11)  CHARACTER SET utf8  NOT NULL;
Query OK, 3 rows affected, 2 warnings (0.10 sec)
Records: 3  Duplicates: 0  Warnings: 2

mysql>     SHOW WARNINGS;
+---------+------+----------------------------------------------------------+
| Level   | Code | Message                                                  |
+---------+------+----------------------------------------------------------+
| Warning | 1366 | Incorrect string value: '\xE0bc' for column 'c' at row 2 |
| Warning | 1366 | Incorrect string value: '\xE1bc' for column 'c' at row 3 |
+---------+------+----------------------------------------------------------+

mysql>     SELECT c, HEX(c) from alters;
+------+----------+
| c    | HEX(c)   |
+------+----------+
| aabc | 61616263 |
| a    | 61       |
| a    | 61       |
+------+----------+

mysql>     -- Observation: text was truncated !  BAD

mysql>     SHOW CREATE TABLE alters\G
Create Table: CREATE TABLE `alters` (
  `c` varchar(11) CHARACTER SET utf8 NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1

案例3:文本错误地存储为latin1列中的utf8;使用" Double ALTER来修复它

mysql>     CREATE TABLE alters (
    ->         c VARCHAR(11)  CHARACTER SET latin1  NOT NULL
    ->     );

mysql>     INSERT INTO alters (c) VALUES ('aabc'), (UNHEX('61c3a06263')), (UNHEX('61c3a16263'));

mysql>     ALTER TABLE alters MODIFY  c VARBINARY(11) NOT NULL;
mysql>     ALTER TABLE alters MODIFY  c VARCHAR(11)  CHARACTER SET utf8  NOT NULL;

mysql>     SELECT c, HEX(c) from alters;
+-------+------------+
| c     | HEX(c)     |
+-------+------------+
| aabc  | 61616263   |
| aàbc  | 61C3A06263 |
| aábc  | 61C3A16263 |
+-------+------------+

mysql>     SHOW CREATE TABLE alters\G
Create Table: CREATE TABLE `alters` (
  `c` varchar(11) CHARACTER SET utf8 NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1

案例4:使用ALTER ... MODIFY;注意LENGTH和CHAR_LENGTH

mysql>     CREATE TABLE alters (
    ->         c VARCHAR(9)  CHARACTER SET latin1  NOT NULL
    ->     );

mysql>     INSERT INTO alters (c) VALUES ('aabc'), (UNHEX('61e06263')),
    ->                    (UNHEX('61e16263')),
    ->                    (UNHEX('61e162633536373839'));

mysql>     SELECT c, HEX(c), LENGTH(c), CHAR_LENGTH(c) from alters;
+------------+--------------------+-----------+----------------+
| c          | HEX(c)             | LENGTH(c) | CHAR_LENGTH(c) |
+------------+--------------------+-----------+----------------+
| aabc       | 61616263           |         4 |              4 |
| aàbc       | 61E06263           |         4 |              4 |
| aábc       | 61E16263           |         4 |              4 |
| aábc56789  | 61E162633536373839 |         9 |              9 |
+------------+--------------------+-----------+----------------+

mysql>     ALTER TABLE alters MODIFY  c VARCHAR(9)  CHARACTER SET utf8  NOT NULL;

mysql>     SELECT c, HEX(c), LENGTH(c), CHAR_LENGTH(c) from alters;
+------------+----------------------+-----------+----------------+
| c          | HEX(c)               | LENGTH(c) | CHAR_LENGTH(c) |
+------------+----------------------+-----------+----------------+
| aabc       | 61616263             |         4 |              4 |
| aàbc       | 61C3A06263           |         5 |              4 |
| aábc       | 61C3A16263           |         5 |              4 |
| aábc56789  | 61C3A162633536373839 |        10 |              9 |
+------------+----------------------+-----------+----------------+

mysql>     SHOW CREATE TABLE alters\G
Create Table: CREATE TABLE `alters` (
  `c` varchar(9) CHARACTER SET utf8 NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

注意:

  • 没有警告,除了我做SHOW的一个案例。
  • 默认表CHARSET未更改,但这不是问题。