Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Desempenho do MySQL:várias tabelas vs. índice em uma única tabela e partições


Criar 20.000 tabelas é uma má ideia. Você precisará de 40.000 mesas em pouco tempo e depois mais.

Chamei essa síndrome de Metadados Tribbles no meu livro SQL Antipatterns . Você vê isso acontecer toda vez que planeja criar uma "tabela por X" ou uma "coluna por X".

Isso causa problemas reais de desempenho quando você tem dezenas de milhares de tabelas. Cada tabela requer que o MySQL mantenha estruturas de dados internas, descritores de arquivos, um dicionário de dados, etc.

Há também consequências operacionais práticas. Você realmente deseja criar um sistema que exija que você crie uma nova tabela toda vez que um novo usuário se inscrever?

Em vez disso, recomendo que você use Particionamento MySQL .

Aqui está um exemplo de particionamento da tabela:
CREATE TABLE statistics (
  id INT AUTO_INCREMENT NOT NULL,
  user_id INT NOT NULL,
  PRIMARY KEY (id, user_id)
) PARTITION BY HASH(user_id) PARTITIONS 101;

Isso oferece a vantagem de definir uma tabela lógica, ao mesmo tempo em que divide a tabela em várias tabelas físicas para acesso mais rápido ao consultar um valor específico da chave de partição.

Por exemplo, quando você executa uma consulta como o seu exemplo, o MySQL acessa apenas a partição correta contendo o user_id específico:
mysql> EXPLAIN PARTITIONS SELECT * FROM statistics WHERE user_id = 1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: statistics
   partitions: p1    <--- this shows it touches only one partition 
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 8
          ref: NULL
         rows: 2
        Extra: Using where; Using index

O método HASH de particionamento significa que as linhas são colocadas em uma partição por um módulo da chave de partição inteira. Isso significa que muitos user_ids são mapeados para a mesma partição, mas cada partição teria apenas 1/N do número de linhas em média (onde N é o número de partições). E você define a tabela com um número constante de partições, para não precisar expandi-la toda vez que conseguir um novo usuário.

Você pode escolher qualquer número de partições até 1024 (ou 8192 no MySQL 5.6), mas algumas pessoas relataram problemas de desempenho quando atingem esse nível.

Recomenda-se usar um número primo de partições. Caso seus valores de user_id sigam um padrão (como usar apenas números pares), usar um número primo de partições ajuda a distribuir os dados de maneira mais uniforme.

Re suas perguntas no comentário:

Para particionamento HASH, se você usar 101 partições como mostro no exemplo acima, qualquer partição terá cerca de 1% de suas linhas em média. Você disse que sua tabela de estatísticas tem 30 milhões de linhas, portanto, se você usar esse particionamento, terá apenas 300 mil linhas por partição. Isso é muito mais fácil para o MySQL ler. Você pode (e deve) usar índices também -- cada partição terá seu próprio índice, e será apenas 1% do tamanho do índice em toda a tabela não particionada.

Portanto, a resposta para como você pode determinar um número razoável de partições é:quão grande é a sua tabela inteira e quão grande você deseja que as partições sejam em média?

O número de partições não precisa necessariamente aumentar se você usar o particionamento HASH. Eventualmente, você pode ter um total de 30 bilhões de linhas, mas descobri que quando seu volume de dados cresce em ordens de magnitude, isso exige uma nova arquitetura de qualquer maneira. Se seus dados crescerem tanto, você provavelmente precisará de fragmentação em vários servidores, bem como particionamento em várias tabelas.

Dito isso, você pode particionar novamente uma tabela com ALTER TABLE:
ALTER TABLE statistics PARTITION BY HASH(user_id) PARTITIONS 401;

Isso precisa reestruturar a tabela (como a maioria das alterações em ALTER TABLE), portanto, espere que demore um pouco.

Você pode querer monitorar o tamanho dos dados e índices nas partições:
SELECT table_schema, table_name, table_rows, data_length, index_length
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE partition_method IS NOT NULL;

Como em qualquer tabela, você deseja que o tamanho total dos índices ativos caiba em seu buffer pool, porque se o MySQL tiver que trocar partes de índices dentro e fora do buffer pool durante consultas SELECT, o desempenho será prejudicado.

Se você usar o particionamento RANGE ou LIST, adicionar, descartar, mesclar e dividir partições é muito mais comum. Consulte http://dev.mysql. com/doc/refman/5.6/en/partitioning-management-range-list.html

Recomendo que você leia a seção do manual sobre particionamento , e também confira esta bela apresentação:Aumente o desempenho Com partições MySQL 5.1 .