Acabei de configurar um sistema de registro que consiste em várias tabelas com o mesmo layout.
Há uma tabela para cada fonte de dados.
Para o visualizador de logs, quero
- UNION todas as tabelas de log ,
- filtrá-los por conta ,
- adicione uma pseudo-coluna para identificação da fonte,
- classificá-los por tempo ,
- e limite-os para paginação .
Todas as tabelas contêm um campo chamado zeitpunkt
que é uma coluna de data / hora indexada.
Minha primeira tentativa foi:
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
'hp' AS source FROM is_log AS l WHERE l.account_id = 730)
UNION
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730)
ORDER BY zeit DESC LIMIT 10;
O otimizador não pode usar os índices aqui porque todas as linhas de ambas as tabelas são retornadas pelas subconsultas e classificadas após o UNION
.
Minha solução alternativa foi a seguinte:
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
'hp' AS source FROM is_log AS l WHERE l.account_id = 730
ORDER BY l.zeitpunkt DESC LIMIT 10)
UNION
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730
ORDER BY l.zeitpunkt DESC LIMIT 10)
ORDER BY zeit DESC LIMIT 10;
Eu esperava que o mecanismo de consulta usasse os índices aqui, já que as duas subconsultas já deveriam ser classificadas e limitadas antes da UNION
, que depois mescla e classifica as linhas.
Eu realmente pensei que seria isso, mas a execução EXPLAIN
da consulta me diz que as subconsultas ainda pesquisam as duas tabelas.
EXPLAINing
as próprias subconsultas me mostram a otimização desejada, mas UNIONing
elas juntas não.
Perdi alguma coisa?
Eu sei que ORDER BY
cláusulas dentro de UNION
subconsultas são ignoradas sem a LIMIT
, mas há um limite.
Edit:
Na verdade, provavelmente também haverá consultas sem aaccount_id
condição.
As tabelas já existem e são preenchidas com dados. Pode haver alterações no layout, dependendo da fonte, então eu quero mantê-las divididas. Além disso, os clientes de log usam credenciais diferentes por um motivo.
Eu tenho que manter um tipo de camada entre os leitores de log e as tabelas reais.
Aqui estão os planos de execução para toda a consulta e a primeira subconsulta, bem como o layout da tabela em detalhes:
(account_id, zeitpunkt)
. Você tem esse índice? O segundo melhor seria (acho) o single(zeitpunkt)
- mas a eficiência, se usada, depende da frequência com que as linhasaccount_id=730
aparecem.UNION DISTINCT
? Não há necessidade de forçar uma classificação e distinção lá, pois os resultados serão diferentes nas subconsultas, devido à coluna de identificação extra. UseUNION ALL
.source
coluna? Dessa forma, você pode evitar seUNION
usar índices em todos os seus dados.UNION ALL
produz um plano de execução diferente.Respostas:
Por curiosidade, você pode experimentar esta versão? Pode ser um truque para o otimizador usar os mesmos índices que as subconsultas usariam separadamente:
Eu ainda acho que o melhor índice que você poderia ter é o composto
(account_id, zeitpunkt)
. Produziria as 10 linhas rapidamente, e nenhum truque seria necessário.fonte
log entries / user
escala serão dimensionados.account_id=?
, mantenha as duas.SELECT * FROM
engana o MySQL para usar os índices?(SELECT ...) AS a
, ele tenta avaliar e otimizar a tabela derivada separadamente das outras tabelas derivadas e depois de toda a consulta.force index
fornecerá uma solução melhor.