Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » PL/SQL

Модерирует : ShIvADeSt

 Версия для печати • ПодписатьсяДобавить в закладки

Открыть новую тему     Написать ответ в эту тему

KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Есть две таблицы:

Код:
CREATE TABLE T1
(
  id numeric(10) not null,
  code number not null,
  CONSTRAINT T1_pk PRIMARY KEY (id)
);
CREATE TABLE T2
(
  id numeric(10) not null,
  type_id number not null,
  CONSTRAINT T2_pk PRIMARY KEY (id)
);

есть запрос:

Код:
select ... from T1, T2
where       T1.id = T2.id
         and T1.code = 47
         and T2.type_id = 2
;

Индексы есть по всем полям.  
План показывает, что оракла сначала по индексу ограничивает T2. Получает дохрена записей. Нет, даже больше. ДОХРЕНА. Потом для каждой записи из T2 делает поиск соответствия  
в T1.  
А в Т1 после  отсечения осталось бы  записей чуток. И если бы оракла  сообразила начать с неё - скорость выросла бы в разы.
Но сбор статистики на базе отключен. Оптимизация только по правилам (решение политическое я могу только смириться)
А для правил, индексы с обеих сторон и оракл не видит ни каких причин что-то менять.
Пляски с изменением порядка перечислениея таблиц, и разными подселектами эффекта не дали. Оракла ухмыляется, раскрывает все скобки, и начинает проверять T2...  

Пятница... может кто навскидку расскажет, как эту стенку пробить...

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 16:06 11-03-2016
zealotfan



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
KDPoid
А почему не inner join T2? Или я так понял таблица T1 меньше то select t1.1,t1.2,(select t2.1 from t2 where t2.id = t1.id) from t1

Всего записей: 234 | Зарегистр. 25-02-2016 | Отправлено: 16:45 11-03-2016 | Исправлено: zealotfan, 17:00 11-03-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Потому что эта заумная скотина раскрывает скобки. И всё равно, сначала по индексу ограничивает T2. А потом для каждой из оставшихся записей делает соответствие с T1.
 
Мне и нужен inner join, он и получается, только ме-е-едленно...
 
Для определённости:
select count(*) from T1 where code = 47
500
 
select count(*) from T2 where type_id = 2
3000000
 
И ваш вариант, и
select ... from (select ...)
легко пережёвываются оптимизатором.  
Оно раскрывает скобки, строит у себя в голове цельную картину, окидывает её всю, говорит: "а-а..., ну понятно", и первым начинает фильтровать T2 по индексу на type_id...
потом 3000000 раз выстраивает соответствие с T1 и только тогда фильтрует по code, оставляя 500 записей.  
 
На мой взгляд - не очень умно. Для оракла - в полном соответствии с правилами оптимизации.

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 19:13 11-03-2016
zealotfan



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
KDPoid
Вы меня неправильно поняли. не select ... from (select ...) , а  
select t1.1,
          t1.2,
         (select t2.1 from t2 where t2.id = t1.id and type_id = 2)  
from t1
where code = 47
Данный запрос должен быстрее вроде выполняться но этот вариант будет работать только в случае если нужно с t2 брать только одно поле

Всего записей: 234 | Зарегистр. 25-02-2016 | Отправлено: 19:27 11-03-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Я пробовал оба варианта.  
На самом деле, даже больше...
И в вашем варианте и во всех остальных упражнениях со скобками, оракл был непоколебим.
Как бы мы искусственно не усложняли синтаксис, оракл, раскрыв скобки, всё равно понимает, что по сути - это две таблицы, склеенные по id и ограниченные по одному значению с каждой стороны. По каждому есть индекс. И он начинает фильтровать по t2.type_id...

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 20:07 11-03-2016
zealotfan



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
KDPoid
Тогда только внешний ключ

Всего записей: 234 | Зарегистр. 25-02-2016 | Отправлено: 20:34 11-03-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
Тогда только внешний ключ

Вообще нет. FK - это же просто constraint.
Вот если бы вы оптимизировали вместо Оракла, ну какая разница, какие там ограничения? Они влияют на возможность выполнения операции и не влияют на её скорость.
В моей практике, наличие fk не влияет на решение оптимизатора оракла, с какой стороны заходить к получению результата.
...
Когда терпение и манеры джентльмена закончились, наступило время подлых трюков.

Код:
 
select ... from T1, T2  
where       T1.id = T2.id  
         and T1.code = 47  
         and T2.type_id + 0 = 2  
;

И тут оракл сломался. T2.type_id + 0 = 2 делает невозможным использование индекса по type_id, значит, единственный остающийся путь - сначала отфильтровать по T1.code
 
На дилетантских замерах скорость возросла в 5 раз.

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 21:51 11-03-2016
zealotfan



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
KDPoid

Цитата:
T2.type_id + 0 = 2 делает невозможным использование индекса по type_id

Так индекс в T2 был на type_id?Я то думал на ID индексы и в Т1, и в Т2

Всего записей: 234 | Зарегистр. 25-02-2016 | Отправлено: 06:11 12-03-2016 | Исправлено: zealotfan, 06:12 12-03-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
Индексы есть по всем полям.

Если бы я был на месте оракла, это и составляло бы для меня проблему.
Есть индекс и по code и по type_id. Без статистики как выбрать, с кого начинать? Для оракла они однаковые. Оказалось, что проще не пытаться подсказать какой лучше, а сделать один хуже. Вплоть до полной неприменимости.

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 06:18 12-03-2016
zealotfan



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
KDPoid
Я работаю с небольшой базой данных в Oracle так что опыта у меня немного по PL/SQL, в основном работаю в firebird и при наличии внешнего ключа оптимизатор взял именно его индекс, кстати в понедельник приду на работу обязательно напишу запрос который я делаю в Oracle и как его можно модернизировать.

Всего записей: 234 | Зарегистр. 25-02-2016 | Отправлено: 06:34 12-03-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Прежде чем пытаться оптимизировать, посмотрите план выполнения...  
Может ваши запросы и так уже близки к идеалу...

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 07:08 12-03-2016
Alexzzy

Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Еще один способ оптимизации - разделение запроса на несколько запросов с использованием промежуточных временных таблиц. Бывает выручает на сложных запросах (особенно при использовании курсоров). Да и читабельность может улучшится. Это по большому опыту с Sybase ASE.
Интересно что сделает Oracle если id из T1 во временную таблицу запихнуть.

Всего записей: 1474 | Зарегистр. 10-07-2013 | Отправлено: 13:29 12-03-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Думаю, оптимизатору слабо выбраться за пределы запроса.  
Временная таблица решила бы проблему, но я рассматривал этот путь как крайнее средство.
Описанная задача - это только часть многоэтажного запроса, выполняющего предварительные проверки перед основным кодом хранимки... Возится с разбиением запроса на куски и временными таблицами не хотелось.  
А теперь и подавно поленюсь пробовать, раз уловка удалась...

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 18:15 13-03-2016
Alexzzy

Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
Думаю, оптимизатору слабо выбраться за пределы запроса.  

Это понятно, интересно не начнет ли он опять по T2 шариться. Ну если лень, то и не надо.

Всего записей: 1474 | Зарегистр. 10-07-2013 | Отправлено: 23:38 13-03-2016
zealotfan



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Подробнее...

Всего записей: 234 | Зарегистр. 25-02-2016 | Отправлено: 08:06 14-03-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
К таблице вопросов нет. Это частый способ хранения древовидных структур.
 
А вот запрос - странный  
Откуда уверенность, что вложенность не может быть  больше четырёх?
 
Может быть, посмотреть в сторону иерархических(они же рекурсивные) запросов?

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 09:39 14-03-2016
Alexzzy

Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
zealotfan
Первый подзапрос лишний - WHERE a.ACCOUNT_ID = ACCOUNT.ACCOUNT_ID.
И, да, такое иерархическими запросами делается. Если СУБД не поддерживает их, то рекурсивной хранимой процедурой.

Всего записей: 1474 | Зарегистр. 10-07-2013 | Отправлено: 13:18 14-03-2016
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
Если СУБД не поддерживает их

Ну, мы, вроде как, в теме PL/SQL... Их поддерживает...
Мой вариант:
Код:
select account_id, trim(sys_connect_by_path(name, ' '))
from account
start with parent is null
connect by prior account_id = parent;

Вроде бы, поменьше букв чем в исходном запросе получилось.  
И по уровню вложенности не так сурово ограничено.

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 13:23 14-03-2016 | Исправлено: KDPoid, 13:27 14-03-2016
zealotfan



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Теперь подзапрос выглядит так:
       (select SUBSTR(SYS_CONNECT_BY_PATH(name,', '),10) AS path
        FROM ACCOUNT a
        START WITH a.PARENT is null
        CONNECT BY PRIOR a.ACCOUNT_ID = a.PARENT)
Результат есть, уменьшение количества букв есть, но вот скорость ниже раза в 2, Оставлю с SYS_CONNECT_BY_PATH т.к. глазу приятнееСпасибо KDPoid

Всего записей: 234 | Зарегистр. 25-02-2016 | Отправлено: 13:26 14-03-2016 | Исправлено: zealotfan, 13:29 14-03-2016
mmt



Junior
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
KDPoid
Конструкцию with ... as ... select не пробовали? на моей практике она сильно ускоряла процесс. В вашем же случае есть условия, которые делают первичный оптимальный отбор возможным  

----------
Все страньше и страньше...

Всего записей: 1058 | Зарегистр. 25-09-2001 | Отправлено: 11:10 18-03-2019
Открыть новую тему     Написать ответ в эту тему

Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » PL/SQL


Реклама на форуме Ru.Board.

Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
Modified by Ru.B0ard
© Ru.B0ard 2000-2024

BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

Рейтинг.ru