X   Сообщение сайта
(Сообщение закроется через 3 секунды)



 

Здравствуйте, гость (

| Вход | Регистрация )

2 страниц V   1 2 >
Открыть тему
Тема закрыта
> Как написать оптимальный вариант INTERSECT для MySQL?
pavelsc
pavelsc
Topic Starter сообщение 27.4.2012, 18:15; Ответить: pavelsc
Сообщение #1


В базе есть таблица в которой прописаны отношения элементов и групп.
CREATE TABLE item_group (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
itemId INT(10) UNSIGNED NOT NULL,
groupId INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;

Ну получается каждый элемент может быть в скольких угодно группах. Каждая группа принадлежит еще к своему уникальному разделу section. Сделал генератор GET формы для фильтрации по группам.
Так как разделов у меня три, то и генерится три селекта со своими группами.
Один из вариантов того что я придумал, это запрос вида:
SELECT itemId FROM item_group WHERE groupId='$group1' OR groupId='$group2' OR groupId='$group3'

В итоге из получившихся значений мы должны взять только те, которые повторяются три раза.
Есть еще такой вариант, но я не проверил его пока:
SELECT itemId FROM item_group WHERE groupId='$group1' AND itemId IN (
SELECT itemId FROM item_group WHERE groupId=='$group2' AND itemId IN (
SELECT itemId FROM item_group WHERE groupId=='$group3'
)
)

В общем надо как UNION только INTERSECT.
0
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
pavelsc
pavelsc
Topic Starter сообщение 27.4.2012, 18:40; Ответить: pavelsc
Сообщение #2


(pavelsc @ 27.4.2012, 21:15) *
Есть еще такой вариант, но я не проверил его пока:
SELECT itemId FROM item_group WHERE groupId='$group1' AND itemId IN (
SELECT itemId FROM item_group WHERE groupId=='$group2' AND itemId IN (
SELECT itemId FROM item_group WHERE groupId=='$group3'
)
)

Ну кстати работает нормально. :goodpost: Но в принципе у меня селектов может быть любое количество, так что буду думать над генератором строки запроса.
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
pavelsc
pavelsc
Topic Starter сообщение 27.4.2012, 19:24; Ответить: pavelsc
Сообщение #3


(pavelsc @ 27.4.2012, 21:40) *
так что буду думать над генератором строки запроса.

Что интересно, получилось так вот:
[PHP]
if(isset($_GET['groups'])){
$groups = array_merge(array_diff($_GET['groups'], array('0'=>'')),array());
}
$sql = '';
$brackets = '';
$groupMaxKey = count($groups) - 1;
for($i=0;$i<=$groupMaxKey;$i++){
$sql .= "SELECT itemId FROM item_group WHERE groupId='".$groups[$i]."' ";
if($i != $groupMaxKey){
$sql .= "AND itemId IN (";
$brackets .= ")";
} else {
$sql .= $brackets;
}
}
[/PHP]
Самое обидно будет если сча придет крутой прогер и скажет что в мускл5.6 есть INTERSECT :)
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
xdrew
xdrew
сообщение 27.4.2012, 21:36; Ответить: xdrew
Сообщение #4


Можно так. Данные:
[IMG]http://funkyimg.com/u2/1621/695/46846627-04-2012_20-31-10.jpg[/IMG]
Запрос:
SELECT DISTINCT itemid
FROM item_group AS ig1
WHERE (

SELECT DISTINCT COUNT( itemid )
FROM item_group AS ig2
WHERE ig2.itemid = ig1.itemid
GROUP BY ig1.itemid
) =3

Результат:
[IMG]http://funkyimg.com/u2/1621/715/74361927-04-2012_20-35-08.jpg[/IMG]
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
Arks
Arks
сообщение 27.4.2012, 22:28; Ответить: Arks
Сообщение #5


xdrew, какой вариант быстрее? Я так полагаю с группировкой есть риск что пробежит по всей таблице(я не имею ввиду возврат результатов клиенту), а
(pavelsc @ 27.4.2012, 21:40) *
Есть еще такой вариант, но я не проверил его пока:

тут его точно нет.
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
xdrew
xdrew
сообщение 27.4.2012, 23:19; Ответить: xdrew
Сообщение #6


На больших выборках должно тормозить (хотя мне кажется, что в этом случае таблица не настолько большая). Ради интереса проверю.
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
pavelsc
pavelsc
Topic Starter сообщение 28.4.2012, 0:24; Ответить: pavelsc
Сообщение #7


xdrew, вот спасибо за пример запроса (просто я любитель, и использую sql по мере потребностей, так что узнал что-то новое), но к сожалению он тут не подойдет.
Дело в том что количество групп в которых может находится элемент может быть любым, а фильтрация может так же проходить с указанием любого числа групп.

На данный момент у меня форма генерирует селекты со списками групп, в зависимости от того, к какому разделу принадлежат группы. Конечно это просто формальность, но просто для удобства.

Из вопросов у меня остался один:
1. Насколько говнокодно выглядит формирование строки sql запроса, и делают ли так вообще нормальные программеры?


(Arks @ 28.4.2012, 01:28) *
Я так полагаю с группировкой есть риск что пробежит по всей таблице

Пробегает в любом случае по всей таблице мой вариант. Ну если появится рабочий вариант запроса, можно посмотреть по числу транзакций что быстрее
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
Arks
Arks
сообщение 28.4.2012, 1:22; Ответить: Arks
Сообщение #8


(pavelsc @ 28.4.2012, 03:24) *
Насколько говнокодно выглядит формирование строки sql запроса, и делают ли так вообще нормальные программеры?

Конечно, только лучше сделать это более читаемым использовав implode сколько-то раз.
пример(отвелеченно):
[PHP]
$ins = array();
$fields = array('id', 'v1', 'v2');
foreach ($vals as $val) {
$insdata = array();
foreach ($fields as $f) $insdata[] = $val[$f];
$ins[] = '('.implode(',',$insdata).')';
}
$ins = 'INSERT INTO '.$tbl.' ('.implode(',',$fields).') VALUES .'.implode(',',$ins);
[/PHP]

По крайней мере лучше используйте не ".=" а array_push и implode для построения запроса/подзапросов, разобраться будет легче откуда что берется.



(pavelsc @ 28.4.2012, 03:24) *
Пробегает в любом случае по всей таблице мой вариант

А я вовсе не про Ваш вариант, я про вариант с выборкой с конечным условием WHERE/HAVING для финального отсева нужных данных для двух приведенных примеров(Вашего с 2 подзапросами и xdrew с группировкой) и внутренние операции mysql-сервера. Часто в этом случае при группировке наблюдается fullscan вместо предварительного создания временной таблички, без видимых причин - как оптимизатор решит. А с фильтрацией по условию IN в подзапросах по индексу - такого нет никогда. Вот про что я, поэтому на реальные результаты и хотелось бы посмотреть.
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
pavelsc
pavelsc
Topic Starter сообщение 28.4.2012, 8:45; Ответить: pavelsc
Сообщение #9


(Arks @ 28.4.2012, 04:22) *
По крайней мере лучше используйте не ".=" а array_push и implode для построения запроса/подзапросов, разобраться будет легче откуда что берется.

В вашем случаем implode хорош тем, что нет проверки надо ли ставить запятую после последнего элемента. :) А по поводу и без такие приемы хороши в JS, т.к. в нем += намного медленнее чем push.
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
Arks
Arks
сообщение 28.4.2012, 20:20; Ответить: Arks
Сообщение #10


(pavelsc @ 28.4.2012, 11:45) *
т.к. в нем += намного медленнее чем push

если говорить о js, то конкатенация через +(+=) медленнее только в IE который на каждую конкатенируемую строчку создает отдельный объект. В остальных монопенисуально.
P.S. впрочем у самого проверить это руки не дошли, возможно я не прав.

А мы используем для совсем сложных запросов не implode а самописный построитель, удобно когда join'ится порядка 16 табличек, кучи полей, кучи фильтров которые могут быть а могу и не быть.
что-то типа
[PHP]
$this->db->select('a.*')->select('b.*, c.field')->from('tbl_1 as a');
$this->db->from('tbl_2 as b')->leftJoinEqual('tbl_3 as c', 'c.ext_id', 'a.id');
if ($filters) {
$this->db->whereEqual('c.field_2',$filters['f']);
$this->db->whereIn('a.field', array(1,2,3));
}
$this->db->groupBy('b.field');

//debug echo $this->db->sql;
$this->db->Marshal('Entity_test');// $this->db->getArray(); $this->db->getGroupArray('c.ext_id'); $this->db->getXML() и т.п.
[/PHP]

+к этому ORM'ка которая делает все еще более автоматическим
Напишите один раз и не мучьтесь с читаемостью кода. Только не забывайте профилировать код, передавать все что нужно по ссылкам и т.п. а то абстракции на php могут жрать немерено ресурсов
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
2 страниц V   1 2 >
Открыть тему
Тема закрыта
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0


Свернуть

> Похожие темы

  Тема Ответов Автор Просмотров Последний ответ
Открытая тема (нет новых ответов) ✅ sms.chekons.com - ⭐ Сервис для получения SMS на реальные номера USA "Non-VoIP, безлим SMS, API" ⭐
Сервис для получения SMS на реальные номера USA
13 Chekon 4040 Сегодня, 11:48
автор: Chekon
Открытая тема (нет новых ответов) Арбитражники, как ведете учет расходов и доходов?
11 Boymaster 1761 Вчера, 23:35
автор: Boymaster
Открытая тема (нет новых ответов) Rebex.io – Ваша инновационная платформа для обмена криптовалюты!
1 Rebex 655 Вчера, 11:50
автор: Rebex
Горячая тема (нет новых ответов) Как вывести деньги в Украине с заблокированного Юмани ?
29 freeax 4781 Вчера, 1:19
автор: sergio11
Открытая тема (нет новых ответов) Какой % отказов нормален для сайта?
11 Aloof 2797 16.4.2024, 12:48
автор: diviner99


 



RSS Текстовая версия Сейчас: 18.4.2024, 17:18
Дизайн