Em Setembro escrevi sobre
as consequências de deixar ao acaso o tamanho e character set de campos VARCHAR. Entretanto gostaria de complementar as observações com o que escrevo abaixo.
A mistura de charsets — como ter uma tabela num charset e um determinado campo dessa tabela com outro charset diferente, por exemplo — deve ser cuidadosamente analisada. Existe alguma probabilidade de ocorrerem complicações, caso se trate esta questão levianamente.
À parte do que se deve ou não fazer, o que eu gostaria era que se compreendesse o benefício que se pode atingir no caso particular da utilização de UUIDs. Já vimos que UTF-8 para este caso particular é um desperdício, mas o que gostaria de demonstrar são se, de facto, compensa alterar campos específicos quando nem todos podem ser alterados.
Vejamos: vão ser criadas 2 tabelas MyISAM em UTF-8, uma com um campo Latin1 e outra com o campo natural, em UTF-8. Vou usar uma tabela que tinha para aqui com 2M de UUIDs apenas para acelerar o processo. Essa tabela,
table_uuid, é original Latin1, embora o foco não seja sobre o carregamento dos dados, mas sim do seu cruzamento entre as duas primeiras:
[mysql]
mysql> create table charset_latin1 ( id char(36) charset latin1, primary key (id) ) charset utf8;
Query OK, 0 rows affected (0.01 sec)
mysql> create table charset_utf8 ( id char(36) charset utf8, primary key (id) ) charset utf8;
Query OK, 0 rows affected (0.01 sec)
mysql> insert into charset_utf8 select id from table_uuid ;
Query OK, 2097152 rows affected (2 min 29.77 sec)
Records: 2097152 Duplicates: 0 Warnings: 0
mysql> insert into charset_latin1 select id from table_uuid ;
Query OK, 2097152 rows affected (50.15 sec)
Records: 2097152 Duplicates: 0 Warnings: 0
[/mysql]
Agora, suponhamos que a tabela
charset_latin1 é uma tabela originalmente em UTF-8, para a qual já fizemos a transformação do campo (que vai albergar UUIDs) para Latin1. O que pretendemos demonstrar são os ganhos/prejuízos do cruzamento de tabelas com as mesmas características, e com diferentes:
[mysql]
mysql> select count(1) from charset_utf8 a, charset_latin1 b where a.id = b.id;
+----------+
| count(1) |
+----------+
| 2097152 |
+----------+
1 row in set (1 min 8.82 sec)
mysql> select count(1) from charset_utf8 a, charset_utf8 b where a.id = b.id;
+----------+
| count(1) |
+----------+
| 2097152 |
+----------+
1 row in set (58.00 sec)
mysql> select count(1) from charset_latin1 a, charset_latin1 b where a.id = b.id;
+----------+
| count(1) |
+----------+
| 2097152 |
+----------+
1 row in set (24.43 sec)
[/mysql]
Ou seja, como já se disse, fazer JOINs com Latin1 é muito rápido, relativamente às outras opções. Mas repare-se quando se cruzam diferentes charsets (1º JOIN): ocorre uma degradação de
19% face ao pior caso.
Ou seja, tendo em conta que estas tabelas podem ser apenas tabelas de relação [quero com isto dizer que não contêm dados que não sirvam senão para cruzamentos/JOINs] é expectável que a performance se degrade sempre que sejam cruzadas com outras cuja chave não esteja no mesmo charset. Deduz-se daqui que existe, portanto,
overhead relativo às conversões de charset durante o JOIN.
Apesar de estarmos perante um
index scan (ie, com os dados todos em
cache), ocorreu-me também experimentar com InnoDB.
[mysql]
mysql> alter table charset_utf8 engine=innodb;
Query OK, 2097152 rows affected (48.18 sec)
Records: 2097152 Duplicates: 0 Warnings: 0
mysql> alter table charset_latin1 engine=innodb;
Query OK, 2097152 rows affected (39.43 sec)
Records: 2097152 Duplicates: 0 Warnings: 0
[/mysql]
Convém ressalvar aqui que fiz uns SELECTs primeiro para ter a certeza que os
datafiles estavam carregados na
buffer pool.
[mysql]
mysql> select count(1) from charset_utf8 a, charset_latin1 b where a.id = b.id;
+----------+
| count(1) |
+----------+
| 2097152 |
+----------+
1 row in set (21.65 sec)
mysql> select count(1) from charset_utf8 a, charset_utf8 b where a.id = b.id;
+----------+
| count(1) |
+----------+
| 2097152 |
+----------+
1 row in set (12.61 sec)
mysql> select count(1) from charset_latin1 a, charset_latin1 b where a.id = b.id;
+----------+
| count(1) |
+----------+
| 2097152 |
+----------+
1 row in set (8.25 sec)
[/mysql]
Ou seja, a conclusão que se pode tirar daqui é que: não só devemos pensar na optimização que se ganha com a escolha do charset, mas também devemos analisar o impacto de não podermos levar a tarefa de reconversão avante na totalidade. A necessidade de cruzar campos com charsets diferentes torna-se, efectivamente, mais penoso. Resta comparar, caso a caso, o benefício que se obtém em queries pouco/nada optimizadas versus o prejuízo de performance que poderá reflectir-se em cruzamentos/JOINs com campos em charsets diferentes.