Meu colega de trabalho quer dividir uma grande tabela de estatísticas de 158 milhões de linhas em stats_jan, stats_feb, ... e usar UNION para selecionar deles para relatórios. Essa é uma prática padrão e é mais rápido do que apenas usar a tabela grande no local e excluir linhas com mais de um ano? A tabela é muitas linhas pequenas.
mysql> describe stats;
+----------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| badge_id | bigint(20) unsigned | NO | MUL | NULL | |
| hit_date | datetime | YES | MUL | NULL | |
| hit_type | tinyint(4) | YES | | NULL | |
| source_id | bigint(20) unsigned | YES | MUL | NULL | |
| fingerprint_id | bigint(20) unsigned | YES | | NULL | |
+----------------+---------------------+------+-----+---------+----------------+
Eu dividi manualmente a tabela e copiei as linhas nas tabelas de mês apropriadas e criei uma consulta UNION gigante. A consulta UNION grande levou 14s versus 4,5m para a consulta de tabela única. Por que muitas tabelas menores levariam um tempo significativamente menor do que uma tabela grande, quando é o mesmo número de linhas no total?
create table stats_jan (...);
create table stats_feb (...);
...
create index stats_jan_hit_date_idx on stats_jan (hit_date);
...
insert into stats_jan select * from stats where hit_date >= '2019-01-01' and hit_date < '2019-02-01';
...
delete from stats where hit_date < '2018-09-01';
...
As tabelas mensais têm de 1,7 milhão de linhas a 35 milhões de linhas.
select host as `key`, count(*) as value from stats join sources on source_id = sources.id where hit_date >= '2019-08-21 19:43:19' and sources.host != 'NONE' group by source_id order by value desc limit 10;
4 min 30.39 sec
flush tables;
reset query cache;
select host as `key`, count(*) as value from stats_jan join sources on source_id = sources.id where hit_date >= '2019-08-21 19:43:19' and sources.host != 'NONE' group by source_id
UNION
...
order by value desc limit 10;
14.16 sec
Não divida a mesa. Use Range Partitionig em vez disso. Estude o Manual de Referência do MySQL 8.0/Particionamento . Use o Manual de Referência do MySQL 8.0 /.../ALTER TABLE Operações de Partição . Tenha em mente que é melhor criar partições para períodos futuros com antecedência (e não se esqueça de criar
LESS THAN MAXVALUE
partição). Criar novas partições e mover dados existentes para elas ao mesmo tempo pode ser mais caro.Não exclua dados permanentemente. Mova-o para uma tabela de arquivo separada. Se você não tiver espaço em disco suficiente - faça um backup dessa tabela de arquivamento, verifique sua validade e, somente se for bem-sucedido, exclua a tabela. Se necessário (será - tenha certeza!), você pode recuperar e usar esses dados.