2016-02-16 1 views
1

Вот мой запрос,Oracle HASH_JOIN_RIGHT_SEMI производительности

SELECT si.* FROM 
FROM SHIPMENT_ITEMS si 
WHERE ID IN (SELECT ID FROM id_map WHERE code = 'A') 
    AND LAST_UPDATED BETWEEN TO_DATE('20150102','YYYYMMDD') - 1 AND TO_DATE('20150103','YYYYMMDD') 

SHIPMENT_ITEMS очень большой стол (10.1TB), id_map очень маленький столик (12 строк и 3 столбцов). Этот запрос проходит через HASH_JOIN_RIGHT_SEMI и занимает очень много времени. SHIPMENT_ITEMS разделяется на столбец ID.

Если удалить подзапрос с твердыми значениями кода, он выполняет гораздо лучше

SELECT si.* FROM 
    FROM SHIPMENT_ITEMS si 
    WHERE ID IN (1,2,3) 
     AND LAST_UPDATED BETWEEN TO_DATE('20150102','YYYYMMDD') - 1 AND TO_DATE('20150103','YYYYMMDD') 

Я не могу удалить подзапрос, поскольку это приводит к жесткому кодированию.

Учитывая, что id_map - очень маленькая таблица, я ожидаю, что оба запроса будут очень похожи. Почему первый занимает гораздо больше времени.

Я на самом деле пытаюсь понять, почему это так плохо.

Я ожидаю, что динамический раздел обрезку произойти здесь, и я не в состоянии выйти с причиной о том, почему его не происходит

https://docs.oracle.com/cd/E11882_01/server.112/e25523/part_avail.htm#BABHDCJG

+1

IN является очень низким на производительности , вы попробовали присоединиться к столам? или использование существует? – sagi

+0

Это поможет добавить планы объяснений для обоих запросов, чтобы узнать, какая разница между ними. Запустите 'объясните план для select ...;', а затем выберите 'select * from table (dbms_xplan.display);' и затем опубликуйте здесь * весь * вывод. Кроме того, являются ли эти реальные запросы запущенными? Похоже, что они вернут миллионы строк, что обычно не имеет смысла. Вы сравниваете время, чтобы вернуть * все * строки или только первые N строк из некоторой среды IDE? –

ответ

1

Try намек no_unnest.

SELECT si.* FROM 
FROM SHIPMENT_ITEMS si 
WHERE ID IN (SELECT /*+ NO_UNNEST */ ID FROM id_map WHERE code = 'A') 
    AND LAST_UPDATED BETWEEN TO_DATE('20150102','YYYYMMDD') - 1 AND TO_DATE('20150103','YYYYMMDD') 

СВО не будет пытаться присоединиться к подзапросу и использовать его как фильтр

+1

Вы также можете объяснить OP и другим людям, которые прочитают это, что именно делает этот намек. – sagi

+0

Подсказка означает, что CBO не будет пытаться присоединиться к подзапросу и использовать его как фильтр – SkyWalker

+0

Не мне, тем, кто его читает .. Подсказка: отредактируйте свой вопрос и напишите его там – sagi

-1

Вместо того, чтобы использовать «в» оператор, использование существует и проверить производительность запросов

SELECT si.* FROM 
FROM SHIPMENT_ITEMS si 
WHERE Exists (SELECT 1 FROM id_map map WHERE map.code = 'A' and map.ID = so.ID) 
    AND LAST_UPDATED BETWEEN TO_DATE('20150102','YYYYMMDD') - 1 AND TO_DATE('20150103','YYYYMMDD')