Trabalhe Multiplataforma sem problemas com o MySQL
Como o MySQL faz referências às tabelas
No MySQL, databases/schemas são diretórios e tabelas são arquivos no filesystem do SO. É fácil verificar criando uma tabela e listando os arquivos do datadir.
Veja este exemplo no Windows:
mysql> CREATE DATABASE meudb;
mysql> USE meudb;
mysql> CREATE TABLE MinhaTabela(id INT PRIMARY KEY NOT NULL AUTO_INCREMENT);
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| meudb |
| mysql |
| performance_schema |
+--------------------+
mysql> SELECT @@datadir;
+-------------------------------------------------+
| @@datadir |
+-------------------------------------------------+
| D:mysql-winmysql-advanced-5.6.25-winx64data |
+-------------------------------------------------+
C:>DIR /b/ad D:mysql-winmysql-advanced-5.6.25-winx64data
meudb
mysql
performance_schema
C:Usersalastori>DIR /b D:mysql-winmysql-advanced-5.6.25-winx64datameudb
db.opt
minhatabela.frm
minhatabela.ibd
O MySQL mantém referências entre as tabelas que podem ser manipuladas via SQL e estes arquivos e vai acessá-los sempre que precisar.
O MySQL é ou não é case sensitive ao referenciar tabelas?
O MySQL nas suas configurações padrão pode se comportar de maneira diferente dependendo do Sistema Operacional que está instalado.
No Windows o filesystem não é case-sensitive e não importa se você varia maísculas ou minúsculas ao referenciar uma tabela. Continuando com exemplo anterior:
mysql> USE meudb;
mysql> SELECT * FROM minhatabela;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
mysql> SELECT * FROM MinhaTabela;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
mysql> SELECT * FROM MINHATABELA;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
No Linux os filesystems normalmente são case-sensitive, portanto uma tabela criada com o nome MinhaTabela é diferente de uma tabela criada como minhatabela que também é diferente de MINHATABELA. Na configuração padrão, qualquer referência às tabelas em comandos SQL deve ser idêntica ao que foi definido na criação da tabela e também à forma que o nome do arquivo está no filesystem do SO. Veja um exemplo em outra instância MySQL, agora no Linux:
mysql> SELECT @@version, @@version_compile_os, @@datadirG
*************************** 1. row ***************************
@@version: 5.6.25-enterprise-commercial-advanced
@@version_compile_os: linux-glibc2.5
@@datadir: /var/lib/mysql/
mysql> CREATE DATABASE meudb;
mysql> USE meudb;
mysql> CREATE TABLE MinhaTabela(id INT PRIMARY KEY NOT NULL AUTO_INCREMENT);
mysql> INSERT INTO MinhaTabela VALUES (),(),();
# ls /var/lib/mysql/meudb
db.opt MinhaTabela.frm MinhaTabela.ibd
mysql> USE meudb;
mysql> SELECT * FROM minhatabela;
ERROR 1146 (42S02): Table 'meudb.minhatabela' doesn't exist
mysql> SELECT * FROM MinhaTabela;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
mysql> SELECT * FROM MINHATABELA;
ERROR 1146 (42S02): Table 'meudb.MINHATABELA' doesn't exist
Note que se você fizer um SELECT * FROM MinhaTabela os arquivos no datadir devem estar nomeados exatamente como MinhaTabela e não poderão ser MINHATABELA, nem minhatabela. Isto pode ser uma fonte de erros quando o ambiente de desenvolvimento é Windows e o de homologação ou produção é Linux. Um exemplo é o MySQL não localizar os arquivos das tabelas existentes e retornar erros parecidos com ERROR 1017 (HY000): Can’t find file: ‘./meudb/minhatabela.frm’ (errno: 2 – No such file or directory).
Como evitar problemas de case sensitive no Linux
Uma solução prática para evitar problemas de portabilidade é tomar duas ações:
1.garantir que o MySQL sempre crie arquivos no filesystem para tabelas usando caracteres minúsculos, em todas plataformas.
2.configurar o MySQL para ignorar maíusculas ou minúsculas (case insensitive) nas operações envolvendo tabelas.
A opção lower_case_table_names=1 implementa estas duas ações. Ou seja, sempre converte os nomes de arquivos para minúsculas no momento da criação da tabela e também relaxa o SQL para aceitar tanto minúsculas quanto maiúsculas para nomes de tabelas.
No Windows a configuração padrão já é lower_case_table_names=1.
mysql> SELECT @@version, @@version_compile_os, @@lower_case_table_namesG
*************************** 1. row ***************************
@@version: 5.6.25-enterprise-commercial-advanced
@@version_compile_os: Win64
@@lower_case_table_names: 1
No Linux a configuração padrão é lower_case_table_names=0.
mysql> SELECT @@version, @@version_compile_os, @@lower_case_table_namesG
*************************** 1. row ***************************
@@version: 5.6.25-enterprise-commercial-advanced
@@version_compile_os: linux-glibc2.5
@@lower_case_table_names: 0
Se você configurar lower_case_table_names=1 em ambas plataformas, será a opção menos propensa a erros. Você não terá que ajustar todas suas queries, pois a comparação de nomes no SQL será case insensitive, independente da plataforma.
Atenção! Antes de configurar lower_case_table_names=1, se você já possui tabelas que contém maíusculas, renomeie-as para minúsculas. Se você não renomear as tabelas ANTES de configurar lower_case_table_names=1, o MySQL não localizará os arquivos das tabelas existentes e retornará um ERROR 1017 (HY000): Can’t find file: ‘…’ (errno: 2 – No such file or directory).
Uma maneira prática de renomear todas as tabelas é gerar os comandos RENAME com esta query abaixo (substitua seu_database):
USE seu_database;
SELECT CONCAT('RENAME TABLE ', table_name, ' TO ' , LOWER(table_name) , ';')
FROM information_schema.tables
WHERE table_schema = 'seu_database';
No nosso exemplo, usando a instância Linux o procedimento seria:
# ls /var/lib/mysql/meudb
db.opt MinhaTabela.frm MinhaTabela.ibd
mysql> SELECT CONCAT('RENAME TABLE ', table_name, ' TO ', LOWER(table_name), ';') FROM information_schema.tables WHERE table_schema='meudb';
+---------------------------------------------------------------------+
| CONCAT('RENAME TABLE ', table_name, ' TO ', LOWER(table_name), ';') |
+---------------------------------------------------------------------+
| RENAME TABLE MinhaTabela TO minhatabela; |
+---------------------------------------------------------------------+
mysql> USE meudb;
mysql> RENAME TABLE MinhaTabela TO minhatabela;
# ls /var/lib/mysql/meudb
db.opt minhatabela.frm minhatabela.ibd
vi /etc/my.cnf
[mysqld]
lower_case_table_names=1
# /etc/init.d/mysql restart
mysql> SELECT @@version_compile_os, @@lower_case_table_namesG
*************************** 1. row ***************************
@@version_compile_os: linux-glibc2.5
@@lower_case_table_names: 1
mysql> USE meudb;
mysql> SELECT * FROM minhatabela;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
mysql> SELECT * FROM MinhaTabela;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
mysql> SELECT * FROM MINHATABELA;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
Note que agora as queries funcionam no Linux independente do case, além dos nomes dos arquivos no filesystem sempre ficarem em minúsculas. Ou seja, o mesmo comportamento que tínhamos no Windows.
Há outras possibilidades para a configuração lower_case_table_names e para saber mais consulte o manual.
Nota: esta recomendação funciona para MySQL 5.0 até 5.6. No MySQL 5.7 o comportamento pode mudar com o novo dicionário de dados. Se você usa replicação, há alguns cuidados adicionais.
Referência