У меня есть таблица items
, из которой я выбираю 40 строк за раз, упорядоченные по popularity
элемента.
Оценка popularity
- это просто downloads/impressions
;
Запрос :
SELECT id, name
FROM items
ORDER BY (SELECT COUNT(*) FROM downloads WHERE item = items.id)/
(SELECT COUNT(*) FROM impressions WHERE item = items.id)
LIMIT 40;
Проблема заключается в том, что выполнение запроса занимает вечность (от 2 до 10 секунд).
На данный момент у нас 25 тыс. Элементов, 18 млн. Показов и 560 тыс. Загрузок.
Мы уже пытались добавить поля downloads
и impressions
в таблицу items
и обновлять счет с помощью триггеров (после вставки в таблицы impressions
и downloads
мы увеличиваем значения ), но у нас были некоторые проблемы с блокировкой.
Есть ли лучший способ оптимизировать этот запрос?
Спасибо.
Редактировать
Вот вывод EXPLAIN
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY items ALL NULL NULL NULL NULL 20496 Using filesort
3 DEPENDENT SUBQUERY impressions ref PRIMARY PRIMARY 4 db.items.id 74 Using index
2 DEPENDENT SUBQUERY downloads ref PRIMARY PRIMARY 4 db.items.id 274 Using index
Таблицы:
CREATE TABLE `items` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(35) DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=24369 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `impressions` (
`item` int(10) unsigned NOT NULL,
`user` char(36) NOT NULL DEFAULT '',
PRIMARY KEY (`item`,`user`),
CONSTRAINT `impression_ibfk_1` FOREIGN KEY (`item`) REFERENCES `items` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `downloads` (
`item` int(10) unsigned NOT NULL,
`user` char(36) NOT NULL DEFAULT '',
PRIMARY KEY (`item`,`user`),
CONSTRAINT `download_ibfk_1` FOREIGN KEY (`item`) REFERENCES `items` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;