Den eneste måde, jeg kan tænke på at få den slags forskel i udførelseshastighed på, ville være at (a) have et indeks på field4
, og (b) har en masse af tomme datablokke; muligvis fra et højvandsmærke sat meget højt ved gentagne direkte vejbelastninger.
Den første forespørgsel ville stadig bruge indekset og fungere som forventet. Men da nulværdier ikke er indekseret, kan indekset ikke bruges til at kontrollere or field4 is null
tilstand, så det ville falde tilbage til en fuld tabelscanning.
Det burde i sig selv ikke være et problem her, da en fuld tabelscanning af 7000 rækker ikke burde tage lang tid. Men da det er det tager så lang tid, at der sker noget andet. En fuld tabelscanning skal undersøge hver datablok, der er allokeret til tabellen, for at se, om de indeholder nogle rækker, og den tid, det tager, tyder på, at der er mange flere blokke, end du behøver for at holde 7000 rækker, selv med inline CLOB-lagring.
Den nemmeste måde at få en masse tomme datablokke på er at have en masse data og derefter slette det meste. Men jeg tror, du sagde i en nu slettet kommentar til et tidligere spørgsmål, at præstationen plejede at være OK og er blevet dårligere. Det kan ske, hvis du laver direct-path inserts , især hvis du 'opdaterer' data ved at slette dem og derefter indsætte nye data i direkte sti-tilstand. Du kunne gøre det med indsættelser, der har /*+ append */
antydning; eller parallelt; eller gennem SQL*Loader. Hver gang du gjorde det, ville højvandsmærket flytte sig, da gamle tomme blokke ikke ville blive genbrugt; og hver gang ville udførelsen af den forespørgsel, der tjekker for nuller, forringes lidt. Efter mange gentagelser ville det virkelig begynde at stige.
Du kan tjekke dataordbogen for at se, hvor meget plads der er allokeret til din tabel (user_segments
osv.), og sammenlign det med størrelsen af de data, du tror, du rent faktisk har. Du kan nulstille HWM ved at genopbygge tabellen, f.eks. ved at gøre:
alter table mytable move;
(helst i et vedligeholdelsesvindue!)
Som en demo kørte jeg en cyklus for at indsætte og slette 7000 rækker med direkte sti over hundrede gange, og derefter kørte jeg begge dine forespørgsler. Den første tog 0,06 sekunder (hvoraf meget er SQL Devleoper overhead); den anden tog 1.260. (Jeg kørte også Gordon's, som fik en lignende tid, da den stadig skal lave en FTS). Med flere gentagelser ville forskellen blive endnu mere markant, men jeg løb tør for plads... Jeg foretog derefter en alter table move
og kør din anden forespørgsel igen, som derefter tog 0,05 sekunder.