2011-06-29 9 views
17

Zajmuję się tworzeniem aplikacji przetwarzającej wiele danych w bazie danych Oracle.
W niektórych przypadkach muszę uzyskać wiele obiektów na podstawie podanej listy warunków i używam SELECT ...FROM.. WHERE... IN..., ale wyrażenie IN akceptuje listę, której rozmiar to maksymalnie 1000 elementów.IN vs OR Oracle, który szybciej?

więc używam OR wyraz zamiast, ale jak obserwować - może to zapytanie (za pomocą OR) jest wolniejsze niż IN (z tej samej listy warunku). Czy to jest poprawne? A jeśli tak, to w jaki sposób zwiększyć szybkość kwerendy?

+0

Czy lista jest statyczna lub pochodzi z zapytania? – Phil

+0

Nie, lista wartości do zapytania została pobrana z zasobu zewnętrznego. Czy istnieje sposób na rozwiązanie tego problemu, ponieważ moja lista jest zbyt duża, może zawierać ponad 100000 elementów –

+1

Tworzysz więc masywny ciąg zapytania zawierający coś w stylu IN (... 9997, 9998, 9999, 1000,1001. ..)? To samo w sobie będzie dużo kosztować, przesłać i przeanalizować. Nieważne możliwości wtrysku sql. –

Odpowiedz

27

IN jest lepszym rozwiązaniem niż OR - OR jest notorycznie złą wersją i może powodować inne problemy wymagające użycia nawiasów w złożonych zapytaniach.

Lepszą opcją niż IN lub OR jest dołączenie do tabeli zawierającej pożądane wartości (lub nie chcesz). Ta tabela dla porównania może być wyprowadzona, tymczasowa lub już istniejąca w twoim schemacie.

+1

Nie, po prostu zapytanie tylko o jedną tabelę. Moja lista może zawierać zbyt wiele pozycji, dlatego nie mogę używać IN. Próbowałem podzielić listę na mniejsze części i wykonać zapytanie na temat partii podlist, ale później muszę zamówić dane w pamięci, to bardzo wolno. –

+0

Czy IN i OR nie są takie same? Innymi słowy, IN rozwija się na OR? Dlatego NOT IN with NULL zawiedzie – gbn

+0

@ gbn: Logicznie, tak. Ale 'IN' jest zoptymalizowane względem użycia' OR' - to coś więcej niż cukier syntaktyczny. –

7

W tym scenariuszu mogłoby zrobić to:

  1. Tworzenie jednej kolumnie globalnej tabeli tymczasowej
  2. Wypełnianie tej tabeli z listą z zewnętrznego źródła (i szybko - kolejny cała dyskusja)
  3. Do zapytanie, dołączając tabelę tymczasową do drugiej tabeli (rozważ dynamiczne próbkowanie, ponieważ tabela tymczasowa nie będzie miała dobrych statystyk)

Oznacza to, że możesz opuścić sortowanie do bazy danych i napisać proste zapytanie.

2

Chciałbym zakwestionować całe podejście. Klient SP musi wysłać 100000 identyfikatorów. Skąd klient otrzymuje te identyfikatory? Wysłanie tak dużej liczby identyfikatorów jako parametru proc będzie i tak bardzo kosztować.

2

Oracle wewnętrznie konwertuje listy IN na listy OR, tak więc nie powinno być żadnych różnic w wydajności. Jedyna różnica polega na tym, że Oracle musi przekształcić INs, ale ma dłuższe łańcuchy do przeanalizowania, jeśli sam dostarczysz OR.

Oto jak to przetestujesz.

CREATE TABLE my_test (id NUMBER); 

SELECT 1 
FROM my_test 
WHERE id IN (1,2,3,4,5,6,7,8,9,10, 
      21,22,23,24,25,26,27,28,29,30, 
      31,32,33,34,35,36,37,38,39,40, 
      41,42,43,44,45,46,47,48,49,50, 
      51,52,53,54,55,56,57,58,59,60, 
      61,62,63,64,65,66,67,68,69,70, 
      71,72,73,74,75,76,77,78,79,80, 
      81,82,83,84,85,86,87,88,89,90, 
      91,92,93,94,95,96,97,98,99,100 
      ); 

SELECT sql_text, hash_value 
FROM v$sql 
WHERE sql_text LIKE '%my_test%'; 

SELECT operation, options, filter_predicates 
FROM v$sql_plan 
WHERE hash_value = '1181594990'; -- hash_value from previous query 

OŚWIADCZENIE SELECT
Tabela pełny dostęp ("ID" = 1 lub "ID" = 2 lub "ID" = 3 lub "ID" = 4 lub "ID" = 5 LUB „identyfikator "= 6 OR" ID "= 7 LUB" ID "= 8 LUB" ID "= 9 LUB" ID "= 10 LUB" ID "= 21 LUB " ID "= 22 LUB" ID "= 23 LUB" ID " = 24 LUB "ID" = 25 LUB "ID" = 26 LUB "ID" = 27 LUB "ID" = 28 LUB "ID" = 29 LUB "ID" = 30 LUB "ID" = 31 LUB "ID" = 32 OR "ID" = 33 OR "ID" = 34 OR "ID" = 35 LUB "ID" = 36 LUB "ID" = 37 LUB "ID" = 38 LUB "ID" = 39 LUB "ID" = 40 OR "ID" = 41 LUB "ID" = 42 LUB "ID" = 43 LUB "ID" = 44 LUB "ID" = 45 LUB "ID" = 46 LUB "ID" = 47 LUB "ID" = 48 OR "ID" = 49 LUB "ID" = 50 LUB "ID" = 51 O R "ID" = 52 LUB "ID" = 53 LUB "ID" = 54 LUB "ID" = 55 LUB "ID" = 56 LUB "ID" = 57 LUB "ID" = 58 LUB "ID" = 59 OR "ID" = 60 LUB "ID" = 61 LUB "ID" = 62 LUB "ID" = 63 LUB "ID" = 64 LUB "ID" = 65 LUB "ID" = 66 LUB "ID" = 67 LUB "ID" = 68 OR "ID" = 69 LUB "ID" = 70 LUB "ID" = 71 LUB "ID" = 72 LUB "ID" = 73 LUB "ID" = 74 LUB "ID" = 75 LUB "ID" = 76 LUB "ID" = 77 LUB "ID" = 78 LUB "ID" = 79 LUB "ID" = 80 LUB "ID" = 81 LUB "ID" = 82 LUB "ID" = 83 LUB " ID "= 84 OR" ID "= 85 LUB" ID "= 86 LUB" ID "= 87 LUB " ID "= 88 LUB" ID "= 89 LUB" ID "= 90 LUB" ID "= 91 LUB" ID "= 92 OR" ID "= 93 LUB " ID "= 94 LUB" ID "= 95 LUB" ID "= 96 LUB" ID "= 97 LUB" ID "= 98 LUB" ID "= 99 LUB " ID "= 100)

+1

Stół, który utworzyłeś, to tabela sterty - bez klucza podstawowego/indeksu –

+0

@OMGPonies Plus 1 w Twojej odpowiedzi, ponieważ nie uwzględniamy jva w odwecie. Wiem, że wielu ludzi by to zrobiło. – Mukus

1

Jeśli utworzyć tabelę z klucza podstawowego:

CREATE TABLE my_test (id NUMBER, 
CONSTRAINT PK PRIMARY KEY (id)); 

i przejść przez te same wybiera, aby uruchomić kwerendę z wielokrotności w wartościach, a następnie pobierania plan wykonania przez wartość mieszania, co masz jest:

SELECT STATEMENT 
INLIST ITERATOR 
INDEX     RANGE SCAN 

to zdaje się sugerować, że gdy masz listę nA i używasz tego z kolumny PK, Oracle przechowuje listę wewnętrznie jako „INLIST”, ponieważ jest bardziej efektywne, aby przetworzyć to, raczej niż przekształcenie go do RNO jak w przypadku nieindeksowanej tabeli.

Używałem Oracle 10gR2 powyżej.