Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > СУБД, общие вопросы > замена left join?


Автор: yezh 29.11.2007, 09:53
Народ, а вы не знаете как можно заменить left join на конструкцию в where? А то left join оч сильно тормозит, и единственный способ оптимизировать время аботы запроса это убрать его

Автор: boevik 29.11.2007, 09:57
в общем случае JOIN нельзя заменить через WHERE, ведь по какому то признаку таблицы должны соединяться.
Возможно улучшить производительность использованием PK и соотвествующх индексов. Копай в эту сторону.

Автор: yezh 29.11.2007, 10:13
Накопано все что можно. Дальше просто некуда. А left join используется для связи двух таблиц, т.е. примерно такая конструкция:
Код

FROM table1 t1 left join table2 t2 on t1.column1 = t2.column1 and t1.column2=t2.column2

Я полагал что такая конструкция может быть заменена на что то другое...

Автор: skyboy 29.11.2007, 10:29
yezh, посмотри то, что тебе выдает http://dev.mysql.com/doc/refman/5.1/en/explain.html. Скорее всего, у тебя в присоединении не используются ключи(индексы), или же у тебя происходит сортировка/группировка большого количества строк.
сделай explain запросу и приведи здесь, что оно возвращает.

Автор: yezh 29.11.2007, 10:41
дело в том, что column1 и column2 - это ключи. А база данных - Pervasive, ключи же используемые нулевые (аля примари). Просто именно эта субд страдает тормознутостью при использовании джоинов, и лучше их на больших таблицах (а в данном случае размер одной таблицы превышает 300 мб) не юзать. 

Автор: skyboy 29.11.2007, 11:37
Цитата(yezh @  29.11.2007,  09:41 Найти цитируемый пост)
то column1 и column2 - это ключи

один составной ключ или два "простых"?

Автор: yezh 29.11.2007, 11:38
один составной

Автор: skyboy 29.11.2007, 11:38
Цитата(yezh @  29.11.2007,  09:41 Найти цитируемый пост)
 Pervasive

это СУБД такая? насчет explain'a - извини, это для mysql.

Добавлено @ 11:46
смотрю, там только http://www.pervasive.com/library/docs/psql/10/sqlref/sqlref-13-5.html доступен, и то - в очень урезанном виде информация выдается...

Добавлено @ 11:48
впрочем, даже у такой скромной штуковины, как http://www.pervasive.com/library/docs/psql/10/sqlref/sqlref-13-1.html есть http://www.pervasive.com/library/docs/psql/10/sqlref/sqlref-13-3.html#wp82883 smile

Автор: yezh 29.11.2007, 12:30
Мде :(. Так то 10 версия, а у нас 8-ка. ПО 8-ке же инфы такой не вижу...
Но это пока ладно, меня больше интересует вопрос, нет ли какого способа переделать запрос? Т.е. можно ли в общем случае отказаться от лефт джоин в пользу условий, и как это может выглядеть?

Автор: skyboy 29.11.2007, 12:42
yezh, потенциально возможно только INNER JOIN "свернуть" до WHERE, да и то - скорость должна быть такая же. 
а запрос,  который ты привел, он и есть полный?

Автор: yezh 29.11.2007, 13:07
Цитата(skyboy @ 29.11.2007,  13:42)
yezh, потенциально возможно только INNER JOIN "свернуть" до WHERE, да и то - скорость должна быть такая же. 
а запрос,  который ты привел, он и есть полный?

Насчет скорости ты не прав: без INNER JOIN запрос работает гораздо быстрее (я так сократил время выполнения запроса с 8 мин до 10 сек)
Почти полный. Используется еще одно поле в left join, но это не ключ.

Автор: skyboy 29.11.2007, 13:31
Цитата(yezh @  29.11.2007,  12:07 Найти цитируемый пост)
без INNER JOIN запрос работает гораздо быстрее (я так сократил время выполнения запроса с 8 мин до 10 сек)

ого! оптимизатор этой СУБД, видать, в полном НЕпорядке.

Автор: Deniz 29.11.2007, 16:18
Цитата(yezh @  29.11.2007,  16:07 Найти цитируемый пост)
Используется еще одно поле в left join, но это не ключ.
Вот об этом поподробнее...

Добавлено через 2 минуты и 49 секунд
skyboy, раньше (давно было, еще на версии 6.15) Btrieve отличался приличной скоростью.
Может что в филармонии не так? Это вопрос к автору.

Автор: yezh 30.11.2007, 10:51
Нате вам запрос полный.

Код

SELECT t1.*, t2.*
FROM table1 t1 LEFT JOIN  table2 t2 ON
  t2.c1=t1.c1 And
  t2.c2=t1.c2 AND
  t2.RefValue = 0 AND t2.AttrID = ''
WHERE t1.Referenc = :id AND t1.Date_Document = :date AND t1.NumDay = :dayNumber

ключи - поля с1 и с2

Автор: skyboy 30.11.2007, 12:30
попробуй убрать констатнтые выражения 
Цитата

t2.RefValue = 0 AND t2.AttrID = ''

быстрее? намного?

Автор: Akina 30.11.2007, 12:38
Цитата(yezh @  30.11.2007,  11:51 Найти цитируемый пост)
t2.RefValue = 0 AND t2.AttrID = ''

А что вообще делают условая отбора в выражении связывания?

Автор: skyboy 30.11.2007, 12:52
Цитата(Akina @  30.11.2007,  11:38 Найти цитируемый пост)
то вообще делают условая отбора в выражении связывания?

подозрительно, правда? возможно, именно из-за этого тормозит.
правда, в WHERE не кинешь - это же LEFT JOIN, потому если перебросить условия в WHERE, то потеряем часть строк, для которых t2.RefValue <> 0 или t2.AttrID <> ''

Автор: Deniz 30.11.2007, 14:56
Цитата(skyboy @  30.11.2007,  15:52 Найти цитируемый пост)
... то потеряем часть строк, для которых ...
а вдруг так быстрее будет?
Может оптимизатор не умеет/не хочет использовать индекс по с1 и с2 при наличии дополнительного условия связывания?

Автор: Akina 30.11.2007, 15:10
Цитата(skyboy @  30.11.2007,  13:52 Найти цитируемый пост)
если перебросить условия в WHERE, то потеряем часть строк, для которых t2.RefValue <> 0 или t2.AttrID <> '' 

да я вообще не понимаю этой фигни в условиях отбора... как оно работать-то будет? с одной стороны left join - значит, все записи из t2 должны войти в результирующий набор независимо ни от чего... с другой - какие-то условия связывания... это что, в результате не будет выполняться связывание с записями, что не отвечают условиям, но в результирующий набор они все одно войдут? с null-ами в t1.*?

по-моему, лучше построить 2 отдельных запроса и слить их результаты...

Автор: yezh 30.11.2007, 15:13
Цитата(skyboy @ 30.11.2007,  13:30)
попробуй убрать констатнтые выражения 
Цитата

t2.RefValue = 0 AND t2.AttrID = ''

быстрее? намного?

А как я уберу константые выражения???? У меня рез-т запроса будет совершенно иной!
2 запроса нельзя сделать по разным причинам. Одна из них - нарушится маппинг рез-тов запроса на класс, чего делать нельзя.
А вот если бы можно было сделать два запроса и слить их при помощи sql (не программными методами), это ьыло ьы замечательно...

Вообще говоря я уже убрал left join, при помощи union'a, однако... запрос работает еще медленнее :(

Добавлено через 8 минут и 34 секунды
Цитата(yezh @ 30.11.2007,  11:51)
[code=sql]
SELECT t1.*, t2.*
FROM table1 t1 LEFT JOIN  table2 t2 ON
  t2.c1=t1.c1 And
  t2.c2=t1.c2 AND
  t2.RefValue = 0 AND t2.AttrID = ''
WHERE t1.Referenc = :id AND t1.Date_Document = :date AND t1.NumDay = :dayNumber

Народ, а может я не понимаю как работает left join?
Мое такое мнение: выбираются все строки из таблицы t1, удовлетворяющие условию в where, затем к рез-ту пристыковываются строки из t2, которые соответствуют условиям в блоке ON

Автор: skyboy 30.11.2007, 15:38
Цитата(Akina @  30.11.2007,  14:10 Найти цитируемый пост)
 но в результирующий набор они все одно войдут? с null-ами в t1.*?

нет. left-join'ится t2, значит, null'ы будут в t2.*

Добавлено через 1 минуту и 34 секунды
Цитата(yezh @  30.11.2007,  14:13 Найти цитируемый пост)
Мое такое мнение: выбираются все строки из таблицы t1, удовлетворяющие условию в where, затем к рез-ту пристыковываются строки из t2, которые соответствуют условиям в блоке ON

именно так. если соотвествующих строк в t2 не окажется, то будут "присоединены" NULL'ы.
Впрочем, такой запрос подозрительно выглядит. может, можно переджелать структуру БД, чтоб избежать таких запросов? 
можно получить информацию по логике запроса? что он вообще моделирует?

Добавлено через 2 минуты и 56 секунд
Цитата(yezh @  30.11.2007,  14:13 Найти цитируемый пост)
А как я уберу константые выражения???? У меня рез-т запроса будет совершенно иной!

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

Автор: yezh 30.11.2007, 15:54
Узкое место? Join. Если просто перенести все условия в where (невзирая на то, что рез-т неполным получится), то работать такой запрос будет порядка 4-х секунд. Если с join - порядка минуты.
Переделать структуру базы я не могу - база от чужого приложения. Т.е. заполняется она именно этим приложением, я лишь беру от туда данные.
Запрос же просто получает действия клиента за поределенный промежуток времени. А таких действий оч много (много клиентов), отсюда огромный размер базы

Добавлено через 1 минуту и 41 секунду
Убирание константных условий не помогло, время выполнения то же.

Автор: Akina 30.11.2007, 16:12
Погоди... ты сказал раньше, что у тебя один составной ключ (что очевидно, двух ключей не бывает) - а связываешь по отдельным полям. Гарантированно одно из двух условий связывания не использует ключа. Попробуй связывать строго по тому выражению, которое используется при построении этого первичного ключа.

Автор: yezh 30.11.2007, 16:33
Ммм.. первазив ето такая база в которой может быть скок угодно ключей .. хоть сто
Если при связывании использовать это выражение, то у меня будут дублироваться записи
Ключ на самом деле не совсем первичный, в том смысле что он не уникальный.
Однако поиск по нему должен выполняться в первую очередь

Автор: skyboy 30.11.2007, 17:29
Цитата(yezh @  30.11.2007,  15:33 Найти цитируемый пост)
первазив ето такая база в которой может быть скок угодно ключей ..

оффтоп: помедитировав, пришел к выводу, что Akina под "ключом" понимает "первичный ключ", а ты - любой индекс. просто несоотвествие "внутренних" терминологий smile
Цитата(yezh @  30.11.2007,  14:54 Найти цитируемый пост)
Убирание константных условий не помогло, время выполнения то же.

походу, ключ при связывании не используется. странно :( А если перейти к inner join - скорость возрастет?

Автор: Akina 30.11.2007, 17:43
Цитата(yezh @  29.11.2007,  11:41 Найти цитируемый пост)
дело в том, что column1 и column2 - это ключи. А база данных - Pervasive, ключи же используемые нулевые (аля примари). 


skyboy, ты медитируешь лучше...

Автор: skyboy 30.11.2007, 17:53
Цитата(Akina @  30.11.2007,  15:12 Найти цитируемый пост)
Гарантированно одно из двух условий связывания не использует ключа.

не знаю, как в Pervasive, а вот MSSQL и MySQL(с чем работал; по идее, все остальные внеяемые СУБД - тоже) если идет условие(в WHERE или JOIN) на все, включенные в составной индекс поля, применяет обработку этого составного индекса.
Не думаю, что Pervasive настолько идиотична, чтоб это игнорировать. А иначе - смысл в составном индексе, если его негде использовать?
Вот только мысль есть: а порядок полей в условии такой же, как порядок объявленного следования в индексе(ключе)? Я с Pervasive не работал, но оптимизатор его подозреваю во всех тяжких. 
--
оффтоп:
ещё тут попутно вопрос:
Цитата(yezh @  29.11.2007,  12:07 Найти цитируемый пост)
без INNER JOIN запрос работает гораздо быстрее (я так сократил время выполнения запроса с 8 мин до 10 сек)

я правильно понял: ты условия связывания в INNER JOIN переместил в секцию WHERE и заработало быстрее? или ты просто объявил INNER JOIN без условия связывания?
--
Цитата(Akina @  30.11.2007,  16:43 Найти цитируемый пост)
skyboy, ты медитируешь лучше...

Что-что?

Автор: Akina 30.11.2007, 17:58
Цитата(skyboy @  30.11.2007,  18:53 Найти цитируемый пост)
если идет условие(в WHERE или JOIN) на все, включенные в составной индекс поля, применяет обработку этого составного индекса.

Да? как я понял из документации, индекс используется только при обработке выражений с теми полями и их частями, которые стоят в начале выражения для построения индекса...

Автор: skyboy 30.11.2007, 18:09
Цитата(Akina @  30.11.2007,  16:58 Найти цитируемый пост)
как я понял из документации, индекс используется только при обработке выражений с теми полями и их частями, которые стоят в начале выражения для построения индекса...

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

не понял только, для чего ты это привел. считаешь, что индекс в запросе yezhа использоваться не может?
Добавлено @ 18:36
yezh, а можно сервер будет обновить?

Автор: yezh 30.11.2007, 18:40
Ок, товарищи, проблема решена. Оказывается, в запросе участвовала не таблица, а структура наложенная на таблицу. Некие же умные программисты в структуру индексов вообще не внесли.
После внесения индексов время работы запросы резко уменьшилось  smile 
Убыв бы таких
Всем огромное спасибо

З.Ы. Кстати, иногда (не знаю почему), бывает такое, что несмотря на все индексы запросы в первазиве работают оч долго (чаще всего при использовании INNER JOIN). Был один такой случай, долго мучались, решили проблему только уберанием этой конструкции.
Это вдруг если кто то захочет использовать Pervasive SQL v8.7  smile 

Автор: Akina 30.11.2007, 18:46
Цитата(skyboy @  30.11.2007,  19:09 Найти цитируемый пост)
не понял только, для чего ты это привел. считаешь, что индекс в запросе yezhа использоваться не может?

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

Однако конструкция вот такого типа:
Код

SELECT t1.*, t2.*
FROM t1 INNER JOIN t2 ON ((t1.v1 & t1.v2) = (t2.v3 &  t2.v4));

при составных индексах по (t1.v1 & t1.v2) и (t2.v3 &  t2.v4) на MS Access и MS SQL летает много быстрее, чем 
Код

SELECT t1.*,t2.*
FROM t1 INNER JOIN t2 ON (t1.v1 = t2.v3) AND (t1.v2 =  t2.v4)




Автор: Deniel_li 6.12.2007, 15:30
если запрос имеет именно такой вид, то смело меняйте на where
у вас нигде нет условий на null  значения, а этот кусочек
Цитата

t2.RefValue = 0 AND t2.AttrID = ''

не подразумевает использование записей из t1 для которых в t2 нет значений

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)