Единственият начин, по който се сещам да получа такава разлика в скоростта на изпълнение, е (а) да имам индекс на field4
, и (б) имат многомного на празни блокове данни; вероятно от висока водна маркировка, зададена много високо чрез повтарящи се натоварвания по директен път.
Първата заявка все още ще използва индекса и ще работи според очакванията. Но тъй като нулевите стойности не се индексират, индексът не може да се използва за проверка на or field4 is null
условие, така че ще се върне към пълно сканиране на таблица.
Това само по себе си не би трябвало да е проблем тук, тъй като пълното сканиране на таблица от 7000 реда не би трябвало да отнеме много време. Но тъй като е отнема толкова време, нещо друго се случва. Пълното сканиране на таблица трябва да изследва всеки блок данни, разпределен към таблицата, за да види дали съдържа някакви редове, а времето, което отнема, предполага, че има много повече блокове, отколкото са ви необходими, за да поберете 7000 реда, дори и с вградено CLOB хранилище.
Най-простият начин да получите много празни блокове данни е да имате много данни и след това да изтриете повечето от тях. Но вярвам, че казахте в вече изтрит коментар по по-ранен въпрос, че производителността беше наред и се влоши. Това може да се случи, ако направите вмъквания на директен път , особено ако „опресните“ данни, като ги изтриете и след това вмъкнете нови данни в режим на директен път. Може да правите това с вмъквания, които имат /*+ append */
намек; или паралелно; или чрез SQL*Loader. Всеки път, когато правите това, знакът за висока вода се мести, тъй като старите празни блокове няма да бъдат използвани повторно; и всеки път производителността на заявката, която проверява за нули, ще се влоши малко. След много повторения това наистина ще започне да се добавя.
Можете да проверите речника на данните, за да видите колко място е разпределено за вашата таблица (user_segments
и т.н.) и го сравнете с размера на данните, които мислите, че всъщност имате. Можете да нулирате HWM чрез повторно изграждане на таблицата, например като направите:
alter table mytable move;
(за предпочитане в период на поддръжка!)
Като демонстрация изпълних цикъл за вмъкване и изтриване на директен път над 7000 реда над сто пъти и след това изпълних и двете ви заявки. Първият отне 0,06 секунди (по-голямата част от които е SQL Devleoper overhead); вторият взе 1.260. (Също така пуснах Gordon's, който получи подобно време, тъй като все още трябва да прави FTS). С повече итерации разликата щеше да стане още по-забележима, но ми свърши мястото... След това направих alter table move
и изпълни повторно втората си заявка, която след това отне 0,05 секунди.