Просмотр продуктов с тегами и GROUP_CONCAT
Я использую Sphinx для полнотекстового поиска в моем приложении. Я использую view
фильтровать данные из products
таблица и Sphinx индексируют это представление. Прямо сейчас у меня есть жестко закодированное поле под таблицей продуктов с соответствующими тегами, но это не так хорошо, поскольку теги могут измениться, и мне придется каждый раз манипулировать жестко закодированным полем.
Поэтому я подумал, что мог бы создать представление с GROUP_CONCAT, перечисляя все связанные теги для меня с синтаксисом, подобным этому:
SELECT p.id AS id, GROUP_CONCAT(t.tag SEPARATOR '|') AS tags,
UNIX_TIMESTAMP(p.created) AS created
FROM products p
INNER JOIN products_tags pt ON pt.product_id = p.id
INNER JOIN tags t ON t.id = pt.tag_id
AND p.deleted = 0
AND (p.images IS NOT NULL OR p.images <> '')
AND p.status LIKE 'listed'
GROUP BY p.id;
Проблема с этим запросом в том, что для его запуска требуются целые годы. Это действительно медленно. Чтобы извлечь только одну запись, требуется до 5 секунд. Это EXPLAIN
выход:
1, SIMPLE, pt, ALL, , , , , 165029, Using temporary; Using filesort
1, SIMPLE, p, eq_ref, PRIMARY, PRIMARY, 4, trych_default.pt.product_id, 1, Using where
1, SIMPLE, t, eq_ref, PRIMARY, PRIMARY, 4, trych_default.pt.tag_id, 1,
Интересно, есть ли способ улучшить запрос или, возможно, лучшее решение моей проблемы. Спасибо!
1 ответ
Вы, вероятно, пропустите индекс. По следующей схеме этот же запрос попадает в индекс для каждой таблицы:
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
`status` varchar(255) NOT NULL DEFAULT 'listed',
`images` varchar(255) DEFAULT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `products_tags` (
`product_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`product_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Вот результаты запроса EXPLAIN:
EXPLAIN SELECT p.id AS id, GROUP_CONCAT(t.tag SEPARATOR '|') AS tags,
UNIX_TIMESTAMP(p.created) AS created
FROM products p
INNER JOIN products_tags pt ON pt.product_id = p.id
INNER JOIN tags t ON t.id = pt.tag_id
WHERE p.deleted = 0
AND (p.images IS NOT NULL OR p.images <> '')
AND p.status LIKE 'listed'
GROUP BY p.id;
+----+-------------+-------+--------+---------------+---------+---------+----------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+----------------+------+-------------+
| 1 | SIMPLE | p | index | PRIMARY | PRIMARY | 4 | NULL | 1 | Using where |
| 1 | SIMPLE | pt | ref | PRIMARY | PRIMARY | 4 | test.p.id | 1 | Using index |
| 1 | SIMPLE | t | eq_ref | PRIMARY | PRIMARY | 4 | test.pt.tag_id | 1 | |
+----+-------------+-------+--------+---------------+---------+---------+----------------+------+-------------+
3 rows in set (0.00 sec)