|
|
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
Добрый день. Есть задача. Есть моя база данных (Oracle 11.2) и удаленная БД (Oracle 11.2), к которой я подключаюсь из своей базы через DBLink. В своей БД я написал некую функцию, которая берет список ID-шников из своей локальной таблицы, и по этому списку ID-шников лезет в удаленную БД и извлекает данные из большой таблицы. Сначала сделал через коллекцию так (пишу схематически, чтобы не загружать тему реальным кодом): Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. И вот тут начинаются приколы. В моей локальной таблице всего 3 записи, в удаленной таблице записей много, но по полю ID есть индекс, он VALID-ный, я проверял. Казалось бы, оракл должен был вытянуть 3 ид-шника из коллекции, передать список из 3-х ид-шников в запрос к удаленной таблице, и поскольку то поле проиндексировано, то запрос должен был выполниться очень быстро. Но в реале запрос выполняется больше минуты. Посмотреть план запроса к удаленной БД не могу, т.к. дблинк - это отдельная транзакция и в плане запроса я увижу только REMOTE, а к удаленной базе у меня нет админского доступа. Когда я делаю вот так: Код: plsql 1. 2. 3. 4. т.е. пишу ид-шники напрямую, запрос выполняется мгновенно. Сделал временно так: Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. Казалось бы все хорошо, но на удаленной базе в кеше запросов будет куча моих однотипных запросов с разными вариациями IN(...), что есть очень плохо. Пытался сделать через параметризированный запрос, определив мой id_list_str как параметр: Код: plsql 1. 2. 3. - не получилось. Видимо, оракл не может объявить параметр типа список, только конкретные значения, а у меня постоянно меняется их количество. У меня остался еще один резервный вариант: в цикле по коллекции выполнять селект к удаленной БД, извлекая по одной записи через параметр, но это решение не очень эффективное, т.к. постоянно будет идти переключение контекста между PL/SQL и SQL, что тоже не очень хорошо. Хотелось бы все-таки обойтись одним запросом к удаленной базе с передачей списка ид-шников, но чтобы при этом не забить library cache этой удаленной базы. Заранее спасибо за помощь. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 30.09.2017, 10:17 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
SQL: Код: plsql 1. 2. 3. 4. это remote SQL ибо у нас одна удаленная таблицa. A вот: Код: plsql 1. 2. 3. 4. 5. это distributed SQL ибо имеем локальную и удаленную таблицы. Смотри план. Скорее всего driving site локальная база. Посему ВСЕ данные удаленной таблицы закачиваются в локальную базу и только потом фильтруются. Помоги оптимазеру вставь хинт /*+ DRIVING_SITE(R) */. Может уговоришь . SY. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 30.09.2017, 13:59 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
cybert Код: plsql 1. 2. 3. 4. 5. Сделай так и все будет ок. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 30.09.2017, 14:21 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
cybertПосмотреть план запроса к удаленной БД не могу, т.к. дблинк - это отдельная транзакция и в плане запроса я увижу только REMOTE"увижу" или "вижу"? Для начала смотреть надо на локальной базе, если плане только REMOTE, то все ок и хинт cardinality должен помочь ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 30.09.2017, 14:26 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
Спасибо Вам большое, DRIVING_SITE(R) помог) Правда, он отлично работает в SQL, когда локальная таблица - физическая. Как только ставлю этот хинт в середину кода на PL/SQL, где в качестве локальной таблицы используется коллекция - этот хинт игнорируется. Ну ничего, я это обойду через Temporary table вместо коллекций. Спасибо еще раз, удачи Вам! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.10.2017, 18:57 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
cybert Код: plsql 1. 2. 3. 4. 5. 6. решается без хинтов, заменой этого блока на: Код: plsql 1. 2. 3. 4. 5. не будет тащить всю удалённую таблицу, а сразу извлечёт то, что нужно ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.10.2017, 12:04 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
Fogelа сразу извлечёт то, что нужно А возможно и больше чем нужно Код: plsql 1. 2. 3. 4. 5. И не факт что "не будет тащить всю удалённую таблицу". Оптимайзер понятия не имеет о размере T, так-что совершенно не факт что WITH сделает R as driving site. SY. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.10.2017, 13:36 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
SYА возможно и больше чем нужно про distinct согласен SYИ не факт что "не будет тащить всю удалённую таблицу". Оптимайзер понятия не имеет о размере T, так-что совершенно не факт что WITH сделает R as driving site. SY. с этим не согласен with для того и придумали, чтобы (в том числе) пошагово наборы данных формировать, поочередно их соединяя, поэтому к обращению к дблинку набор из with уже известен и тип соединения оптимизатор в любом случае выберет, не вытаскивая всю таблицу с удалённой базы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.10.2017, 17:18 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
Fogelwith для того и придумали, чтобы (в том числе) пошагово наборы данных формировать, поочередно их соединяя И на каком заборе это написано? Это отимайзер решает материализовать WITH (вернее каждое CTE по отдельности) или нет. Но даже если и материализует то что? Получим соединение temporary table с удаленной таблицей что ничем это отличается от исходной ситуации. Оптимайзер понятия не имеет о размере temporary table и считает cardinality (если не ошибаюсь) по рaзмеру блока БД а посему как ни крути а либо CARDINALITY либо DRIVING_SITE. SY. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.10.2017, 20:48 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
cybert, c коллекцией тоже можно, только я забыл что тут еще одну хитрость надо сделать: Код: plsql 1. 2. 3. 4. 5. ps. Джонатан как всегда спасает ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.10.2017, 21:49 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
SYFogelwith для того и придумали, чтобы (в том числе) пошагово наборы данных формировать, поочередно их соединяя И на каком заборе это написано? Это отимайзер решает материализовать WITH (вернее каждое CTE по отдельности) или нет. Но даже если и материализует то что? Получим соединение temporary table с удаленной таблицей что ничем это отличается от исходной ситуации. Оптимайзер понятия не имеет о размере temporary table и считает cardinality (если не ошибаюсь) по рaзмеру блока БД а посему как ни крути а либо CARDINALITY либо DRIVING_SITE. SY. на заборе моего опыта. возможно, мне не попадались иные кейсы. но когда дблинк, материализация сте на локале идёт по умолчанию и получается "выдёргивание" по индексируемому полю нужных значений. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.10.2017, 21:59 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
Fogelно когда дблинк, материализация сте на локале идёт по умолчанию и получается "выдёргивание" по индексируемому полю нужных значений. Да ну? Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. Ну где " материализация сте на локале идёт по умолчанию и получается "выдёргивание" по индексируемому полю нужных значений"? SY. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.10.2017, 22:45 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
Материализация вообще тут не работает, т.е. с коллекцией и remote: +materialize Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. materialize+driving_site+cardinality Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. c workaround от Jonathan Lewis Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. Тут нужно пояснить: 1. Во-первых, я надеялся на FULL REMOTE Statement, но из-за волшебных kokbf$, это не проходит (логично предположить, что просто не стали париться с проверкой соответствия типов коллекций) 2. Материализация не работает. Я уже говорил, что решение о материализации принимается не стоимостным алгоритмом, а захардкоденными правилами, и, скорее все, этот тип находится в исключениях, т.к. я пробовал стандартные известные мне правила - и добавить предикат, и обратиться к V несколько раз - не помогло... 3. DRIVING_SITE не работает для коллекций, т.к. нужен инициатор вызова remote statements, передающий бинды 4. Workaround от Льюиса, конечно, рабочий, и в большинстве случаев он будет хорошо подходить, но у него есть и минус - remote statement будет вызываться столько же раз сколько к нему лукапов будет, а это, естественно, будет медленнее при большом кол-ве обращений (и само кол-во выполнений, и кол-во сетевых раундтрипов...) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.10.2017, 23:24 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
В целом, все это еще и зависит от версий - волшебные kokbf и их ограничения меняются от версии к версии... Я тестировал на 12.2 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.10.2017, 23:28 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
xtender, спасибо за подробные пояснения ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.10.2017, 09:08 |
|
||
|
Можно ли использовать параметр в секции IN() запроса
|
|||
|---|---|---|---|
|
#18+
Спасибо еще раз всем огромное) Сделал, как советовал xtender, прочитав статью Джонатана ( https://jonathanlewis.wordpress.com/2010/10/11/distributed-objects/). Все получилось, финальный тестовый код работает отлично. SY.: Workaround от Льюиса, конечно, рабочий, и в большинстве случаев он будет хорошо подходить, но у него есть и минус - remote statement будет вызываться столько же раз сколько к нему лукапов будет, а это, естественно, будет медленнее при большом кол-ве обращений (и само кол-во выполнений, и кол-во сетевых раундтрипов...) - да, бесспорно, но это в 100 раз лучше, чем мое временное решение, где я в цикле PL/SQL вызывал Select, выдирая из ремоут таблицы по одной записи, т.е. еще и переключение контекста шло) Еще раз спасибо всем участникам за помощь, удачи всем! финальный тестовый код: Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.10.2017, 00:37 |
|
||
|
|

start [/forum/topic.php?fid=52&msg=39530738&tid=1885146]: |
0ms |
get settings: |
5ms |
get forum list: |
13ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
146ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
56ms |
get tp. blocked users: |
1ms |
| others: | 208ms |
| total: | 444ms |

| 0 / 0 |
