Каковы последствия производительности Oracle IN Clause без соединений?

У меня есть запрос в этой форме, который будет в среднем принимать ~ 100 в элементах предложения, а в некоторых редких случаях – 1000 элементов. Если более 1000 элементов, мы разделим предложение in до 1000 (максимум Oracle).

SQL находится в форме

SELECT * FROM tab WHERE PrimaryKeyID IN (1,2,3,4,5,...) 

Таблицы, которые я выбираю, огромны и будут содержать миллионы строк, чем то, что находится в моей статье. Меня беспокоит то, что оптимизатор может выбрать сканирование таблицы (наша база данных не имеет актуальной статистики – да, я знаю …)

Есть подсказка, которую я могу передать, чтобы принудительно использовать первичный ключ – БЕЗ зная имя индекса первичного ключа, возможно, что-то вроде … / * + DO_NOT_TABLE_SCAN * /?

Существуют ли какие-либо творческие подходы к возврату данных,

  1. Мы выполняем наименьшее количество круглых поездок
  2. Мы читаем наименьшее количество блоков (на уровне логического IO?)
  3. Будет ли это быстрее ..
 SELECT * FROM tab WHERE PrimaryKeyID = 1 UNION SELECT * FROM tab WHERE PrimaryKeyID = 2 UNION SELECT * FROM tab WHERE PrimaryKeyID = 2 UNION .... 

    Если статистика в вашей таблице является точной, очень маловероятно, что оптимизатор предпочтет выполнять сканирование таблицы, а не использовать индекс первичного ключа, если в WHERE есть только 1000 жестко закодированных элементов. Лучшим подходом было бы собрать (или установить) точную статистику по вашим объектам, поскольку это должно привести к тому, что хорошие вещи произойдут автоматически, а не попытаются сделать много гимнастики, чтобы работать с неправильной статистикой.

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

    Если вы создаете инструкцию SQL с переменным количеством жестко запрограммированных параметров в предложении IN , вы, вероятно, будете создавать проблемы с производительностью для себя, наводя свой общий пул нерасширяемым SQL и заставляя базу данных тратить много времени жестко разбирает каждый вариант отдельно. Было бы намного эффективнее, если бы вы создали единый общий SQL-запрос, который можно было бы разобрать раз. В зависимости от того, откуда берутся значения предложения IN , это может выглядеть примерно так:

     SELECT * FROM table_name WHERE primary_key IN (SELECT primary_key FROM global_temporary_table); 

    или

     SELECT * FROM table_name WHERE primary_key IN (SELECT primary_key FROM TABLE( nested_table )); 

    или

     SELECT * FROM table_name WHERE primary_key IN (SELECT primary_key FROM some_other_source); 

    Если вы попали в единый расширяемый SQL-оператор, то, помимо того, что вы избегаете затрат на постоянное повторное разбирательство оператора, у вас будет несколько вариантов форсирования определенного плана, который не включает в себя модификацию оператора SQL. В разных версиях Oracle есть разные варианты стабильности плана: в зависимости от вашей версии хранятся контуры , управление планами SQL и профили SQL среди других технологий. Вы можете использовать их для форсирования конкретных планов для конкретных операторов SQL. Однако, если вы продолжаете генерировать новые SQL-запросы, которые должны быть повторно проанализированы, становится очень сложно использовать эти технологии.