Três mesas:
product
: com colunas: ( a, g, ...a_lot_more... )
a: PK, clustered
g: bit-column
main
: com colunas: ( c, f, a, b, ...a_lot_more... )
c: PK, clustered
f: bit-column
(a, b): UQ
lookup
com colunas: ( a, b, c, i )
(a, b): PK, clustered
a: FK to product(a)
c: UQ, FK to main(c)
i: bit-column
Não consigo encontrar bons índices para a associação:
FROM
product
JOIN
lookup
ON lookup.a = product.a
JOIN
main
ON main.c = lookup.c
WHERE
product.g = 1
AND
main.f = 1
AND
lookup.i = 1
AND lookup.b = 17
Eu tentei um índice de cobertura product (g, a, ...)
e ele é usado, mas não com resultados espetaculares.
Algumas combinações de índices na lookup
tabela produzem planos de execução com mesclagem de índices, com leve ganho de eficiência em relação ao plano anterior.
Existe alguma combinação óbvia que estou perdendo?
Um re-design da estrutura poderia ajudar?
O DBMS é o MySQL 5.5 e todas as tabelas estão usando o InnoDB.
Tamanhos da tabela:
product: 67K , g applied: 64K
main: 420K , f applied: 190K
lookup: 12M , b,i applied: 67K
mysql
mysql-5.5
optimization
ypercubeᵀᴹ
fonte
fonte
Respostas:
Isso me dói ...
Eu tive que usar tabelas temporárias com o InnoDB antes. Carregue-os com filtros, crie um índice, junte-se a essas tabelas temporárias.
O problema, na minha opinião, é se o InnoDB tiver apenas o algoritmo Nested Join: os otimizadores de consultas RDBMS crescidos têm mais a usar. Isso se baseia na tentativa de executar cargas do tipo Data Warehouse no InnoDB.
As tabelas temporárias arrastam a complexidade geral para baixo do nível do otimizador de consultas MySQL ...
fonte
main
) desnormalizando os dados paralookup
?Parece um produto cartesiano. Refazer os critérios JOIN
SUGESTÃO ALTERNATIVA
Isso pode parecer pouco ortodoxo e provavelmente cheira a SQL Anitpattern, mas aqui vai ...
Não movi as subconsultas
product.g = 1
emain.f = 1
para as subconsultas porque são campos de bits e apenas fará uma varredura de tabela no momento. Mesmo se os campos de bits fossem índices, o Query Optimizer simplesmente ignoraria esse índice.Claro, você pode mudar
SELECT * FROM lookup
paraSELECT a FROM lookup
se o seu SELECT não precisar de nadalookup
Talvez envolva a, b na junção entre pesquisa e main se isso faz sentido
ou coloque de volta ce junte-se a três colunas (Índice nas três colunas de
main
elookup
)fonte
main.f
eproduct.g
??? Se a cardinalidade demain.f
eproduct.g
para o valor for 1 for menor que 5% das linhas da tabela, um índicemain.f
eproduct.g
poderá ser justificável.main.f
eproduct.g
for 2, você poderá abandonar esses índices.