Existem várias regras a seguir para fazer cadernos otimizados. Infelizmente não está escrito em livros de estudo porque este conhecimento não é uma compilação do manual do MySQL, mas é resultado de uma longa experiência e luta contra a lentidão.
Eu não falo sobre índices em campos onde WHERE é usado. E outras coisas assim. Isso não é dica profissional 🙂 É meio regular. Portanto, tentarei ir além das sugestões simples.
- Pode ser que algumas das minhas explicações não sejam completamente corretas quando tento explicar o processo por trás, mas em geral estamos falando sobre resultados.
Para entender a ideia principal, vamos tomar duas tabelas.
Comercial
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`email` varchar(100) NOT NULL DEFAULT '',
`password` varchar(100) NOT NULL DEFAULT '',
`block` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `idx_name` (`name`),
KEY `idx_block` (`block`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `users` (`name`, `email`, `password`, `block`) VALUES ('jon', 'test@test.com', '123', 0);
INSERT INTO `users` (`name`, `email`, `password`, `block`) VALUES ('Eddy', 'eddy@test.com', '321', 1);
e atributos do usuário
CREATE TABLE `user_profiles` (
`user_id` int(11) NOT NULL,
`profile_key` varchar(100) NOT NULL,
`profile_value` varchar(255) NOT NULL,
UNIQUE KEY `idx_user_id_profile_key` (`user_id`,`profile_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `user_profiles` (`user_id`, `profile_key`, `profile_value`)
VALUES (1, 'moderator', '1'), (2, 'moderator', '0'),
(1, 'email_sent', '1'), (2, 'email_sent', '1'),
(1, 'registered', '2012-01-01 00:00:00'), (2, 'registered', '2012-01-02 00:00:00');
Todos nós sabemos que o pior caso é quando fornecemos o uso de temporário e de classificação de arquivo em uma linha em explain. Todas as consultas parecem estar OK até você começar a usar ORDER BY
ou / eGROUP BY
Isso é o que vamos resolver. Para reestruturar a consulta para que ela tenha apenas o uso de were .
Agora vamos examinar os erros mais sérios na construção de consultas.
1. Evite o uso LEFT JOIN
se seus apelidos usados em WHERE
. Esta é a lição mais importante que tive que aprender.
SELECT * FROM
users AS u
LEFT JOIN user_profiles AS p ON p.user_id = u.id
WHERE 1
AND u.block = 1
AND (p.profile_key = 'moderator' AND p.profile_value = 1)
ORDER BY u.name
Melhor usar subconsultas neste caso.
SELECT * FROM
users AS u
WHERE 1
AND u.block = 1
AND u.id IN (SELECT user_id
FROM user_profiles AS p
WHERE p.user_id = u.id
AND p.profile_key = 'moderator'
AND p.profile_value = 1)
ORDER BY u.name
Deixe-me explicar mais sobre isso. É como se criássemos uma tabela temporária, inseríssemos todos os moderadores e então a usássemos como uma tabela de índice. E este princípio principal da otimização de consulta. Olhe para as subconsultas.
Esta técnica também permitirá que você evite o uso GROUP BY
. Porque você usa mesmo que seja apenas 4 registros serão retornados. E é uma grande dor de cabeça.id IN()
id IN(1,2,1,3,4,2,2,2)
GROUP BY
dica pro-pro 🙂 Eu descobri que às vezes é mais rápido executar a subconsulta separadamente e formar string como e inseri-la como string, mas não como subconsulta.
1,2,8,47,12
IN()
2. Evite classificar por campo em JOIN
. Como, por exemplo, tentar ordenar por valor de perfil cadastrado.
SELECT * FROM
users AS u
LEFT JOIN user_profiles AS p ON p.user_id = u.id AND p.profile_key = 'registered'
WHERE 1
AND u.block = 1
ORDER BY p.profile_value ASC
melhor usar subconsultas.
SELECT u.*,
(SELECT profile_value
FROM user_profiles
WHERE user_id = u.id
AND profile_key = 'registered') as reg
FROM
users AS u
WHERE 1
AND u.block = 1
ORDER BY reg DESC