Eu gostaria de obter as últimas (ou últimas) linhas de uma tabela (chamada CONTENT) contendo mais de 10 milhões de linhas. A consulta contém junções em 2 outras tabelas e é extremamente lenta. Estas são as definições da tabela e minha consulta:
CREATE TABLE `USER` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`value` varchar(64) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY (`value`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
CREATE TABLE `GUID` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`value` char(36) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `value` (`value`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
CREATE TABLE `CONTENT` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned DEFAULT NULL,
`guid_id` int(11) unsigned DEFAULT NULL,
`timestamp` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `guid` (`guid_id`),
KEY `user_id` (`user_id`),
KEY `timestamp` (`timestamp`),
CONSTRAINT `CONTENT_ibfk_4` FOREIGN KEY (`guid_id`) REFERENCES `GUID` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `CONTENT_ibfk_5` FOREIGN KEY (`user_id`) REFERENCES `USER` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Consulta:
SELECT
`CONTENT`.`id`,
`GUID`.`value` AS `guid_value`,
`USER`.`value` AS `user_value`
FROM `CONTENT`, `USER`, `GUID`
WHERE `CONTENT`.`user_id` = `USER`.`id`
AND `CONTENT`.`guid_id` = `GUID`.`id`
ORDER BY `CONTENT`.`timestamp` DESC LIMIT 1
# even without ORDER BY the query is slow as seen by explain command
Estes são os resultados do comando Explain copiado como INSERT:
+------+-------------+---------+--------+---------------+---------+---------+-----------------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+--------+---------------+---------+---------+-----------------------------+-------+----------------------------------------------+
| 1 | SIMPLE | GUID | index | PRIMARY | value | 37 | NULL | 16329 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | CONTENT | ref | guid,user_id | guid | 5 | MANAGER.GUID.id | 293 | Using where |
| 1 | SIMPLE | USER | eq_ref | PRIMARY | PRIMARY | 4 | MANAGER.CONTENT.user_id | 1 | |
+------+-------------+---------+--------+---------------+---------+---------+-----------------------------+-------+----------------------------------------------+
A consulta é inutilizável, então estou dividindo-a em 2 consultas. Primeiro, recupero o CONTENT.id de interesse e, segundo, coloco uma WHERE CONTENT.id = x
cláusula adicional na instrução SELECT. Parece que na consulta original o otimizador MariaDB não entende que eu só preciso de 1 linha, então ele faz o produto cartesiano com cada linha na tabela GUID. Dividir a consulta em 2 subconsultas é o caminho a seguir? Alguém pode confirmar que a operação cartesiana do produto é de fato a operação que está causando problemas? (primeira linha de resultados do comando de explicação)
EXPLIQUE da consulta de Ricks:
+------+-------------+------------+--------+----------------------+-------------------+---------+-----------------------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+------------+--------+----------------------+-------------------+---------+-----------------------------+---------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 2 | |
| 1 | PRIMARY | CONTENT | eq_ref | PRIMARY,guid,user_id | PRIMARY | 4 | c.id | 1 | Using where |
| 1 | PRIMARY | USER | eq_ref | PRIMARY | PRIMARY | 4 | MANAGER.CONTENT.user_id | 1 | |
| 1 | PRIMARY | GUID | eq_ref | PRIMARY | PRIMARY | 4 | MANAGER.CONTENT.guid_id | 1 | |
| 2 | DERIVED | CONTENT | index | NULL | timestamp | 6 | NULL | 9474301 | Using index |
+------+-------------+------------+--------+----------------------+-------------------+---------+-----------------------------+---------+-------------+
Por favor, veja o quão rápido isso é executado e o que o Explain diz: