MySQL вопрос к специалистам

12
WebSee
На сайте с 12.11.2007
Offline
66
1093

Приветствую, уважаемые специалисты!

Столкнулся с одной задачкой на оптимизацию, объясню вкратце:

есть две таблицы:

`list` с полями `id`, `name`

`param` с полями `id`, `list_id`, `value`

Здесь идет связь один ко многим (`list`.`id`=`param`.`list_id`)

В таблице `param` хранятся параметры записей из таблицы `list`

Так же имеются значения нужных параметров: $param1=23, $param2='seo' и т.п.

Собственно теперь задача:

Выбрать из таблицы `list` только те записи, для которых значения параметров из таблицы `param` соответствуют заданным параметрам: $param1, $param2 и т.п.

Мое решение:

SELECT `list`.`id`, `list`.`name` 

FROM `list`
LEFT JOIN `param` AS p1 ON (p1.`list_id`=`list`.`id`)
LEFT JOIN `param` AS p2 ON (p2.`list_id`=`list`.`id`)
WHERE p1.`id`=1 AND p1.`value`=$param1 AND p2.`id`=2 AND p2.`value`=$param2

Т.е. для каждого значения параметра делаем свою выборку из одной и той же таблицы параметров.

В примере всего два параметра, а представляете что будет, если параметров, хотя бы 15 :eek:

Вот и хочется узнать мнение экспертов возможно ли оптимизировать такой запрос для большого числа параметров?

Встань и иди!
F
На сайте с 12.09.2003
Offline
120
#1

если условий WHERE немного (до 30-50) их можно формировать циклом

можно вот так:


"select * from `list` LEFT JOIN `param` ON (`list`.`id`=`param`.`list_id`) where p1.`id`=1 and ...

по сути у тебя получается соединенная таблица по id-соответствию, без перечисления условий в твоем случае - никак

Jeck
На сайте с 20.07.2006
Offline
82
#2

Что то я не пойму зачем в запросе "p1.`id`=1" и "p2.`id`=2" если по условию что вы привели то вот так делается


SELECT `list`.`id`, `list`.`name`
FROM `list`
LEFT JOIN `param` AS p1 ON (p1.`list_id`=`list`.`id`)
WHERE p1.`value` IN ($param1, $param2, $param3)

Но это если скажем меньше 50 параметров, если больше - через временную таблицу.

Мой блог (http://jeck.ru)
WebSee
На сайте с 12.11.2007
Offline
66
#3
Faster:
если условий WHERE немного (до 30-50) их можно формировать циклом

Формировать циклом имеется ввиду, через другой язык (например PHP) ?

Если так, то это понятно, нужно как-то сам MySQL-запрос оптимизировать, а то он громоздкий получается.

В твоем примере не определены p1 ...

F
На сайте с 12.09.2003
Offline
120
#4

да через php

WebSee
На сайте с 12.11.2007
Offline
66
#5
Jeck:
Что то я не пойму зачем в запросе "p1.`id`=1" и "p2.`id`=2"

Каждый параметр имеет свой смысл, нужно чтоб значение соответствовало конкретному параметру, а не любому.

Наверно пример не совсем корректно представлен, немного подправил:

SELECT `list`.`id`, `list`.`name` 
FROM `list`
LEFT JOIN `param` AS p1 ON (p1.`list_id`=`list`.`id`)
LEFT JOIN `param` AS p2 ON (p2.`list_id`=`list`.`id`)
WHERE p1.`type`='day' AND p1.`value`=$param1 AND p2.`type`='text' AND p2.`value`=$param2

Добавил к таблице `param` поле `type`, так думаю будет более понятней.

А насчет IN я тоже думал, но в данном случае это не подходит, вот если бы можно было использовать пары, что-то типа (`type`, `value`) IN (('day', $param1), ('type', $param2)), то это и было бы оптимальное решение, не знаю можно ли так?

Jeck
На сайте с 20.07.2006
Offline
82
#6

Значит делать надо вот так...


CREATE TEMPORARY TABLE `temp` LIKE `param`

Потом вставляете в эту таблицу данные


INSERT INTO `temp` VALUES ('','day',$param1),('','type',$param2)

И после этого вот такой запрос


SELECT `list`.`id`, `list`.`name`
FROM `list`
LEFT JOIN `param` AS p ON (p.`list_id`=`list`.`id`)
LEFT JOIN `temp` AS t ON (t.`type` = p.`type` AND t.`value` = p.`value`)

Вот примерно так... возможно надо что то подправить.

D
На сайте с 21.06.2006
Offline
168
#7

SELECT list_id,COUNT(*) AS cnt FROM param WHERE value IN($param1,$param2,...)

GROUP BY list_id HAVING cnt>=PARAM_COUNT

На деле может оказаться быстрее разделить запрос на атомарные части, что-то обсчитывать кодом.

Appstorespy - платформа анализа мобильных сторов | Publa.io - готовая инфраструктура для приема платежей и оплаты рекламных кабинетов в бурже
WebSee
На сайте с 12.11.2007
Offline
66
#8

Jeck, хороший вариант, только в данном случае выберутся записи в которых присутствует хотя бы одно совпадение с параметром, аналогично:

WHERE p1.`type`='day' AND p1.`value`=$param1 OR p2.`type`='text' AND p2.`value`=$param2

а нужно

WHERE p1.`type`='day' AND p1.`value`=$param1 AND p2.`type`='text' AND p2.`value`=$param2

Dash, оператор GROUP BY `list_id` понравился, кажется нужно в этом направлении двигаться, пока только не понятно как.

А выражение value IN (...) будет пересекаться с другими типами параметров, некоторые параметры равны между собой, но соответствующие ($param1, $param2,...) не обязательно.

Т.е. если в таблице `param` есть записи (1, 'day', 23), (2, 'text', 23), и нужные параметры имеют значения $param1=23, $param2='seo', то запись выберется, хотя не соответствует желанному.

Jeck
На сайте с 20.07.2006
Offline
82
#9

WebSee, выложите небольшие дампы таблиц что бы можно было нормально поковырять :)

D
На сайте с 21.06.2006
Offline
168
#10
WebSee:

Dash, оператор GROUP BY `list_id` понравился, кажется нужно в этом направлении двигаться, пока только не понятно как.
А выражение value IN (...) будет пересекаться с другими типами параметров, некоторые параметры равны между собой, но соответствующие ($param1, $param2,...) не обязательно.
Т.е. если в таблице `param` есть записи (1, 'day', 23), (2, 'text', 23), и нужные параметры имеют значения $param1=23, $param2='seo', то запись выберется, хотя не соответствует желанному.

Я приводил запрос для примера

Будут выбраны записи с одновременным удовлетворением всех условий(для этого счетчик)

12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий