Оптимизация запроса

LONGMAN

Dark Side of the Moon..
Оптимизация запроса

запрос:
PHP:
SELECT `p`.*
FROM `shoppingcart_products` AS `p`
LEFT JOIN `shoppingcart_products_data` AS `d` ON `p`.`id` = `d`.`itemid`
LEFT JOIN `shoppingcart_products_categories` AS `pc` ON `pc`.`pid` = `p`.`id`
LEFT JOIN `shoppingcart_categories` AS `cc` ON `cc`.`id` = `pc`.`cid`
LEFT JOIN `shoppingcart_currency` AS `cur` ON `cur`.`id` = `p`.`currency`
LEFT JOIN `shoppingcart_manufacturers_data` AS `m` ON `m`.`itemid` = `p`.`manufacturer`
LEFT JOIN `shoppingcart_users` AS `u` ON `u`.`id` = `p`.`added_by`
GROUP BY `p`.`id`
ORDER BY `p`.`date` DESC
LIMIT 10
Explain:
PHP:
id 	select_type 	table 	type 	possible_keys 	key 	key_len 	ref 	rows 	Extra 
1	SIMPLE	p	index	NULL	date	8	NULL	4591	Using temporary
1	SIMPLE	d	ref	itemid	itemid	4	shopdb.p.id	2	Using index
1	SIMPLE	pc	ref	PRIMARY	PRIMARY	4	shopdb.p.id	2	Using index
1	SIMPLE	cc	eq_ref	PRIMARY	PRIMARY	4	shopdb.pc.cid	1	Using index
1	SIMPLE	cur	eq_ref	PRIMARY	PRIMARY	4	shopdb.p.currency	1	Using index
1	SIMPLE	m	ref	itemid	itemid	4	shopdb.p.manufacturer	1	Using index
1	SIMPLE	v	eq_ref	PRIMARY	PRIMARY	4	shopdb.p.added_by	1	Using index
Для вывода 10 записей перебирать 4591 это нормально?
P.S. Как тут нормально оформить SQL код и Explain?
 

Gas

может по одной?
1. В explain'е показывается не точное количество рядов которое будет затронуто, точное значение можно посмотреть в slow query log (если не ошибаюсь, то в INFORMATION_SCHEMA PROFILING и SHOW PROFILES нет такой информации);

2. Не всегда explain учитывает значение LIMIT'а, то есть в rows может быть указано 100тыщ миллионов, а на самом деле запрос вытягивает только 10 записей. У тебя в explain'е нет using filesort, вероятно что количестсво просматриваемых строк меньше 4591;

3. Не понимаю зачем у тебя в запросе куча LEFT JOIN'ов, которые совсем никак не используются;

4. explain попробуй вставлять не в SQL/PHP bb-тегах , а в CODE.
 

prolis

Новичок
5. Почему именно LEFT JOIN
6. GROUP BY ID ORDER BY DATE - ну это как бы вообще ни о чём запрос
 

LONGMAN

Dark Side of the Moon..
Автор оригинала: Gas
3. Не понимаю зачем у тебя в запросе куча LEFT JOIN'ов, которые совсем никак не используются;
Используется в селекте, просто я вырезал что бы уменшить код

-~{}~ 29.07.10 21:42:

Автор оригинала: prolis
5. Почему именно LEFT JOIN
6. GROUP BY ID ORDER BY DATE - ну это как бы вообще ни о чём запрос
LEFT JOIN потаму что выбираю продукты. 10 новых продуктов. А GROUP BY p.id потаму что там мултикатегории
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
LONGMAN
как я понял, то prolis, тебя спросил о том, почему LEFT а не просто JOIN? не INNER и не STRAIGHT))))
 

Adelf

Administrator
Команда форума
LONGMAN
нет.
Ты все-таки прочитай что-нибудь про SQL, прежде чем ваять запросы :) И уж тем более оптимизировать.
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
LONGMAN
ни разу, JOIN в общем случае аналог inner join
http://kreker.org/items/5#inner

-~{}~ 29.07.10 23:48:

ЗЫ: Помнитя как же меня гонял по запросам Виктор Иванович Котеликов он же vikot, когда я в mnogo.ru считал статистику для МТС по их базе в 55Гб. Мдяяяя, было время
 

LONGMAN

Dark Side of the Moon..
Adelf
Будет сделано :)

-~{}~ 30.07.10 01:14:

c0dex
Спасибо за ссылку. 55гб база был MySQL??
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
Да, был мускуль, там было в районе 60Гб, еще ~5 занимал "мусор".
 

Wicked

Новичок
джоины - зло

запрос разбивается на несколько таких:

select * from shoppingcart_products order by `date` desc limit 10;

select * from shoppingcart_products_data where item_id in (1, 2, 10, 20, ...);

и т.д.

PS: в нормальных ORMках это делается на раз-два
 

prolis

Новичок
Автор оригинала: LONGMAN
А GROUP BY p.id потаму что там мултикатегории
Ну вот у тебя допустим один продукт в двух категориях, при группировке по ID ты сколько записей с одним продуктом хотел бы получить?
 

LONGMAN

Dark Side of the Moon..
Wicked
Для каждого джоина так??

-~{}~ 01.08.10 02:15:

Автор оригинала: prolis
Ну вот у тебя допустим один продукт в двух категориях, при группировке по ID ты сколько записей с одним продуктом хотел бы получить?
Один
 

Wicked

Новичок
Вурдалак
не вижу большого смысла, т.к. в данном случае это:
1) избавляет от группировки, и, соответственно, от using temporary
2) позволяет выбрать order by `date` limit x, y тупо по индексу
что в итоге работает моментально.

а в общем случае дает еще прилично ништячков:
http://softsearch.ru/i/download/mmug.pdf

LONGMAN
да...
но если тебе не хочется переделывать запрос, то можно обойтись такой техникой:
[SQL]SELECT `p`.*
FROM `shoppingcart_products` AS `p`
INNER JOIN (SELECT `id` FROM `shoppingcart_products` ORDER BY `date` LIMIT 10) AS `p2` on (`p`.`id` = `p2`.`id`)
LEFT JOIN `shoppingcart_products_data` AS `d` ON `p`.`id` = `d`.`itemid`
LEFT JOIN `shoppingcart_products_categories` AS `pc` ON `pc`.`pid` = `p`.`id`
LEFT JOIN `shoppingcart_categories` AS `cc` ON `cc`.`id` = `pc`.`cid`
LEFT JOIN `shoppingcart_currency` AS `cur` ON `cur`.`id` = `p`.`currency`
LEFT JOIN `shoppingcart_manufacturers_data` AS `m` ON `m`.`itemid` = `p`.`manufacturer`
LEFT JOIN `shoppingcart_users` AS `u` ON `u`.`id` = `p`.`added_by`
GROUP BY `p`.`id`[/SQL]
 

Wicked

Новичок
fixxxer
окей

Вурдалак
а что с ними не так?

например, кол-во категорий для каждого продукта в корзине:
SELECT `pc`.`pid`, COUNT(*) FROM `shoppingcart_products_categories` AS `pc` WHERE `pc`.`pid` IN (...) GROUP BY `pc`.`pid`;
Или я тебя не понял?
 

Вурдалак

Продвинутый новичок
Wicked, ну да, только стандартными средставами ORM ты такой запрос не оформишь? Да и всё равно есть задачи, где вот так по-хорошему не сделаешь. Скажем, выборка категорий любой вложенности с кол-вом товаров в каждой категории.

-~{}~ 03.08.10 08:12:

Имею в виду nested sets, если чё.
 

Wicked

Новичок
ну встроенных в ORM средств для этого нету, но наверняка можно будет сделать методы для модели/коллекции, в которые завернуть более-менее произвольный запрос в виде критерия или dql.

Либо прибегнуть к чему-нибудь типа этого - http://www.propelorm.org/wiki/Documentation/1.5/Behaviors/aggregate_column - будет даже лучше с точки зрения производительности.
 
Сверху