## Only 1 query which returns 10 rows.
## It took about 66 secs
mysql> explain
SELECT al.log_id , al.user_id , al.page_name ,
al.section_name , al.submit_time , al.url ,
alfm1.value as 'source_env' ,
alfm2.value as 'website_id' ,
alfm3.value as 'index_id'
FROM admin_logs al
LEFT OUTER JOIN
(select * from admin_log_field_map where field_id = 3351
) alfm1 ON al.log_id = alfm1.log_id
LEFT OUTER JOIN
(select * from admin_log_field_map where field_id = 911
) alfm2 ON al.log_id = alfm2.log_id
, admin_log_field_map alfm3
WHERE 1=1
AND al.page_name='Index Management'
AND al.log_id=alfm3.log_id
AND alfm3.field_id=891
AND alfm3.value='jewelry'
ORDER BY al.log_id DESC;
+----+-------------+---------------------+--------+--------------------+------------+---------+---------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+--------+--------------------+------------+---------+---------------------+-------+----------------------------------------------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 0 | const row not found |
| 1 | PRIMARY | al | ref | idx_622,idx_pgname | idx_pgname | 78 | const | 27720 | Using where; Using temporary; Using filesort |
| 1 | PRIMARY | alfm3 | ref | idx_1533,idx_0311 | idx_1533 | 10 | cms.al.log_id,const | 1 | Using where |
| 1 | PRIMARY | <derived3> | ALL | NULL | NULL | NULL | NULL | 35358 | |
| 3 | DERIVED | admin_log_field_map | ref | idx_0311 | idx_0311 | 5 | | 33098 | Using where |
| 2 | DERIVED | admin_log_field_map | ref | idx_0311 | idx_0311 | 5 | | 1 | Using where |
+----+-------------+---------------------+--------+--------------------+------------+---------+---------------------+-------+----------------------------------------------+
6 rows in set (0.20 sec)
mysql>
mysql>
mysql> show create table admin_logs\G
*************************** 1. row ***************************
Table: admin_logs
Create Table: CREATE TABLE `admin_logs` (
`row_mod` datetime DEFAULT NULL,
`row_create` datetime DEFAULT NULL,
`log_id` int(11) DEFAULT NULL,
`user_id` varchar(50) COLLATE latin1_bin DEFAULT NULL,
`page_name` varchar(75) COLLATE latin1_bin DEFAULT NULL,
`section_name` varchar(125) COLLATE latin1_bin DEFAULT NULL,
`submit_time` datetime DEFAULT NULL,
`url` varchar(255) COLLATE latin1_bin DEFAULT NULL,
`source_environment` varchar(255) COLLATE latin1_bin DEFAULT NULL,
`log` longtext COLLATE latin1_bin,
UNIQUE KEY `idx_622` (`log_id`),
KEY `idx_pgname` (`page_name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin
1 row in set (0.00 sec)
mysql> \! hostname
fol-piwikdb01.dca.ftd.untd.com
mysql> show create table admin_log_field_map\G
*************************** 1. row ***************************
Table: admin_log_field_map
Create Table: CREATE TABLE `admin_log_field_map` (
`row_mod` datetime DEFAULT NULL,
`row_create` datetime DEFAULT NULL,
`log_id` int(11) DEFAULT NULL,
`field_id` int(11) DEFAULT NULL,
`value` varchar(255) COLLATE latin1_bin DEFAULT NULL,
UNIQUE KEY `idx_1533` (`log_id`,`field_id`),
KEY `idx_0311` (`field_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin
1 row in set (0.00 sec)
how to get better performance using above query?
Primeiro, vamos reescrever a consulta descartando a sintaxe de junção implícita ANSI-89 e removendo as tabelas derivadas:
Também movi algumas das condições da
WHERE
cláusula para a cláusula de respostaON
, para que fique mais claro quais índices você precisa.Das duas junções externas, fica claro que da tabela
admin_log_field_map
, você só precisa das linhas com um fixofield_id
(3351 ou 911) e apenas as colunaslog_id
(para fazer a junção) evalue
(para serem retornadas naSELECT
lista):Portanto, um bom índice para essas 2 junções à esquerda seria
(field_id, log_id, value)
A terceira junção (interna) para
admin_log_field_map
, é diferente. Você só precisa das linhas com fixofield_id
(891) e fixovalue
('jóia') e depoislog_id
(para fazer o join). Depois disso, nada é realmente necessário para aSELECT
lista (ovalue
já é conhecido e corrigido):Portanto, um bom índice para essas 2 junções à esquerda seria
(field_id, value, log_id)
Para a
admin_logs
tabela, você já tem um índice ativado(page_name)
, então provavelmente será usado para aWHERE
condição.Então, o que você pode fazer é adicionar esses dois índices: