在 MySQL 或 Postgres 中使用混合 table 字符集时,我们会遇到性能问题吗?
Can we have performance issues when using mixed table charsets in MySQL or in Postgres?
我正在处理一个包含不同字符集表的数据库。由于它是一个大数据库,我想知道它是否会导致性能问题。是的,数据库通常做的通常值比较是 JOIN 并且完成比较整数,但是除了某些字符集采用更大的 space 之外,我们是否可以遇到具有不同字符集的表的任何其他性能问题?
如果您使用不兼容的排序规则进行字符串比较,则这些比较不能使用字符串列上的索引。我在字符串列上执行 JOIN 时看到过这种情况,并且加入的 tables 具有不同的排序规则(当然,如果它们也具有不同的字符集,它们也是不同的排序规则)。
但是你说你的联接是在整数列上,而不是在字符串列上。所以在你的情况下加入应该不是问题。
如果您的 table 字符集与您的会话字符集不匹配,则在对字符串列进行查找时也可能会遇到性能问题。
示例:我的 table 是用 utf8mb4 定义的,但我将会话设置为 utf8,因此字符串文字将为 utf8。看起来是一个无害的改变,对吧?
mysql> set names utf8;
mysql> explain select * from mytable where text = 'abc123';
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | mytable | NULL | ref | text | text | 83 | const | 1 | 100.00 | NULL |
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
我想 utf8 字符串 'abc123' 有一个明确的方法可以提升为 utf8mb4 以匹配它所比较的列。
但是如果我强制使用 utf8mb4 不支持的特定排序规则,我发现它必须执行 table-扫描并逐行比较,而不是索引查找:
mysql> explain select * from mytable where text = 'abc123' collate utf8_general_ci;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | mytable | NULL | ALL | NULL | NULL | NULL | NULL | 10 | 100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
隐式排序规则和显式排序规则之间存在差异。假设我将我的会话设置为使用没有清晰路径到 utf8mb4 的东西:
mysql> set names latin1;
mysql> explain select * from mytable where text = 'abc123';
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | mytable | NULL | ref | text | text | 83 | const | 1 | 100.00 | NULL |
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
到目前为止一切顺利,但如果我明确说明排序规则:
mysql> explain select * from mytable where text = 'abc123' collate latin1_general_ci;
ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (latin1_general_ci,EXPLICIT) for operation '='
底线是您应该使用相同的字符集和排序规则以使您的生活更轻松。将它用于所有 table 和会话。
在现代,很难想出使用 utf8mb4 以外的任何理由。
P.S。 Space 应该不是问题。 UTF-8 字符集允许 多字节字符,但它们不会扩展适合单个字节的字符大小。 UTF-8 是一种可变宽度字符编码。所以 ASCII 范围 (0-127) 中的字符无论如何都存储在一个字节中。阅读 UTF-8 on wikipedia 了解详情,它有很好的解释。
MySQL:
对于 zip_code (postal_code),存储为字符串(CHAR
或 VARCHAR
),大多数字符集同样适用。但是,当 JOINing
在这样的列上时, 排序规则 必须相同。
- 如果相同,则可以使用该列的索引。
- 如果不是,则索引无用,查询必须扫描整个table.
由于排序规则包含字符集,这也强制字符集相同。
排序规则的选择比较少。但是,如果字符串中可以有字母(postal_code、country_code 等),您需要决定是否强制 tables(和用户查询)使用特定的大小写.
- 排序规则
..._bin
将大小写视为不同的:'de' 将不匹配 'DE'(对于德国)。
- 排序规则
..._ci
是“不区分大小写”的,因此它们会匹配。
我正在处理一个包含不同字符集表的数据库。由于它是一个大数据库,我想知道它是否会导致性能问题。是的,数据库通常做的通常值比较是 JOIN 并且完成比较整数,但是除了某些字符集采用更大的 space 之外,我们是否可以遇到具有不同字符集的表的任何其他性能问题?
如果您使用不兼容的排序规则进行字符串比较,则这些比较不能使用字符串列上的索引。我在字符串列上执行 JOIN 时看到过这种情况,并且加入的 tables 具有不同的排序规则(当然,如果它们也具有不同的字符集,它们也是不同的排序规则)。
但是你说你的联接是在整数列上,而不是在字符串列上。所以在你的情况下加入应该不是问题。
如果您的 table 字符集与您的会话字符集不匹配,则在对字符串列进行查找时也可能会遇到性能问题。
示例:我的 table 是用 utf8mb4 定义的,但我将会话设置为 utf8,因此字符串文字将为 utf8。看起来是一个无害的改变,对吧?
mysql> set names utf8;
mysql> explain select * from mytable where text = 'abc123';
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | mytable | NULL | ref | text | text | 83 | const | 1 | 100.00 | NULL |
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
我想 utf8 字符串 'abc123' 有一个明确的方法可以提升为 utf8mb4 以匹配它所比较的列。
但是如果我强制使用 utf8mb4 不支持的特定排序规则,我发现它必须执行 table-扫描并逐行比较,而不是索引查找:
mysql> explain select * from mytable where text = 'abc123' collate utf8_general_ci;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | mytable | NULL | ALL | NULL | NULL | NULL | NULL | 10 | 100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
隐式排序规则和显式排序规则之间存在差异。假设我将我的会话设置为使用没有清晰路径到 utf8mb4 的东西:
mysql> set names latin1;
mysql> explain select * from mytable where text = 'abc123';
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | mytable | NULL | ref | text | text | 83 | const | 1 | 100.00 | NULL |
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
到目前为止一切顺利,但如果我明确说明排序规则:
mysql> explain select * from mytable where text = 'abc123' collate latin1_general_ci;
ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (latin1_general_ci,EXPLICIT) for operation '='
底线是您应该使用相同的字符集和排序规则以使您的生活更轻松。将它用于所有 table 和会话。
在现代,很难想出使用 utf8mb4 以外的任何理由。
P.S。 Space 应该不是问题。 UTF-8 字符集允许 多字节字符,但它们不会扩展适合单个字节的字符大小。 UTF-8 是一种可变宽度字符编码。所以 ASCII 范围 (0-127) 中的字符无论如何都存储在一个字节中。阅读 UTF-8 on wikipedia 了解详情,它有很好的解释。
MySQL:
对于 zip_code (postal_code),存储为字符串(CHAR
或 VARCHAR
),大多数字符集同样适用。但是,当 JOINing
在这样的列上时, 排序规则 必须相同。
- 如果相同,则可以使用该列的索引。
- 如果不是,则索引无用,查询必须扫描整个table.
由于排序规则包含字符集,这也强制字符集相同。
排序规则的选择比较少。但是,如果字符串中可以有字母(postal_code、country_code 等),您需要决定是否强制 tables(和用户查询)使用特定的大小写.
- 排序规则
..._bin
将大小写视为不同的:'de' 将不匹配 'DE'(对于德国)。 - 排序规则
..._ci
是“不区分大小写”的,因此它们会匹配。