2011-07-05 16 views
7

Wykonuję proste zapytanie "wybierz" w pętli Java, co pokazano poniżej. Rozmiar listy może wzrosnąć nawet do 10000+. Jak mogę poprawić szybkość zapytań? Doznajemy dowolnego przykładu lub rady. Dzięki.Optymalizacja prędkości podczas wykonywania kwerendy "wybierz" w dużej pętli

Należy zauważyć, że muszę pobrać wszystkie dane w każdej kolumnie tej tabeli, dlatego używa się gwiazdki (*).

List<String> valueList = .... 
Connection conn = null; 
PreparedStatement ps = null; 
ResultSet rs = null; 

try { 
    DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); 
    conn = DriverManager.getConnection(dbURL, dbUsername, dbPassword); 
    for (int m = 0; m < valueList.size() ; m++) {  
     String sql = "SELECT * FROM WORKSHEET WHERE " + sheetId + " = '" +  
         valueList.get(m) + "'"; 
     ps = conn.prepareStatement(sql); 
     rs = ps.executeQuery(); 
     // retreive data....   
    } 
} 

Edycja: Na końcu jest kilka sposobów na przyspieszenie tej kwerendy. Używam drugiej metody, ponieważ w przyszłości zapobiegnie to błędowi ORA-04031.

  1. Użyj sparametryzowanej kwerendy "WYBIERZ" z klauzulą ​​"IN".
  2. Utwórz tabelę zagnieżdżoną i odtwórz tablicę/listę elementów pochodzących z JDBC do utworzonej tabeli zagnieżdżonej.
  3. Utwórz tabelę tymczasową i wstaw listę przedmiotów. Następnie wykonaj JOIN do głównej tabeli (1 zapytanie) i uzyskaj wyniki.
+9

[SQL Injection Hooooorrrrraayay!] (Http://bobby-tables.com/) * Sidenote: * Użycie sparametryzowanych zapytań dałoby również lepszą wydajność. – Bobby

+2

Podałeś powód * - jakiegokolwiek powodu, dla którego nie używasz sparametryzowanego zapytania? –

+0

Zmniejszenie całkowitej liczby zapytań wykonanych przez odtworzenie wielu par identyfikatorów SheetID w każdym zapytaniu ("GDZIE para 1 lub para 2 lub para 3 itd ...") zmniejszyłoby część narzutów. –

Odpowiedz

6

Są dwie rzeczy, które należy rozważyć, gdy próbuje przyspieszyć proces:

  1. Wykonanie tej kwerendy tylko raz na zawsze sheetid na
  2. Upewnij się, że wykonując tę ​​samą kwerendę za każdym razem, przez nie hardcoding wartości in. Ponieważ wartości te ewentualnie się zmieniają, każde zapytanie będzie wyglądać jak poprzednie zapytanie, ale z tylko kilkoma różnymi wartościami. Nie pozwoli to Oracle na ponowne wykorzystanie poprzedniego zapytania i prowadzi do nieosiągalnego SQL w puli współużytkowanej. Spowoduje to zapełnienie puli współużytkowanej. Zrób to wystarczająco długo, a otrzymasz komunikaty o błędach ORA-04031.

Jedną z metod jest użycie typów SQL. Oto przykład w PL/SQL. Możesz użyć tej samej zasady w Javie.

Najpierw utwórz tabelę z dziesięć tysięcy sheetId użytkownika:

SQL> create table worksheet (sheetid) 
    2 as 
    3 select level 
    4  from dual 
    5 connect by level <= 10000 
    6/

Table created. 

Tworzenie typu SQL:

SQL> create type mynumbers is table of number; 
    2/

Type created. 

W kodzie, wypełnić instancję typu SQL z wartościami w „valuelist "i użyj operatora TABLE, aby przekształcić typ w wartości tabeli:

SQL> declare 
    2 valuelist mynumbers := mynumbers(23,124,987,6123,8923,1,7139); 
    3 begin 
    4 for r in 
    5 (select ws.sheetid 
    6  from worksheet ws 
    7   , table(valuelist) vl 
    8  where ws.sheetid = vl.column_value 
    9 ) 
10 loop 
11  dbms_output.put_line(r.sheetid); 
12 end loop; 
13 end; 
14/
1 
23 
124 
987 
6123 
7139 
8923 

PL/SQL procedure successfully completed. 

Teraz masz tylko jeden SQL w Twojej puli współużytkowanej i tylko jedno wykonanie tego zapytania, zamiast tysięcy.

4

Czas poświęcony jest głównie na przygotowanie i wykonanie zapytań.

Jeśli zamiast tego uruchomisz pojedynczą kwerendę, która zwróci wszystkie wyniki, spowoduje to o wiele szybsze działanie.

tj:

String where = "(1=0) " 
// first build the where string 
for (int m = 0; m < valueList.size() ; m++) { 
    where = where + " OR (" + sheetId + " = '" + valueList.get(m) + "'"; 
    } 
// then run a single query 
sql = "SELECT * FROM WORKSHEET WHERE " + where; 
ps = conn.prepareStatement(sql); 
rs = ps.executeQuery(); 
// retrieve and handle data. .... 
+1

Hmmm ... Myślisz, że tak? Powiedział "Rozmiar listy może dorastać do 10000+". –

+1

Wciąż bym to robił! Kosztem uruchomienia każdego zapytania jest to, co obecnie go spowalnia. Zakładam, że będzie również działać instrukcja IN: budowanie kodu SQL oznaczającego WHERE sheetID IN (1,2,3,4 ...) To jest rzeczywiście ładniejsze i dużo krótsze. – Eljakim

+0

Myślę, że używając OR, unikasz limitu 1000 elementów dla klauzuli IN w Oracle, co jest dobre. Ale zdecydowanie użyłbym StringBuilder dla wszystkich konkatenacji String. – sudocode

3

Musisz przygotować zapytanie sql IN statment a następnie wykonać kwerendę tylko raz ...

+0

Instrukcja IN nie może działać ze względu na limit 1000. –

+0

W każdym razie próbuję go rozwiązać, dzieląc je na "OR" i "UNION" –

0

ja nie wiem, czy będzie to poprawa, ale można spróbować wybieranie wszystkich rekordów i sprawdzanie z kodem Java, jeśli pasuje sheetId. To jest coś, co powinieneś wiedzieć, co jest lepsze.

1

Oracle może przyjąć do 1000 parametrów w klauzuli IN. Więc jeśli użyjesz przygotowanej instrukcji, zredukujesz liczbę iteracji 1000-krotnie. Wystarczy podzielić listę na 1000 elementów.

2

Oto kilka innych pomysłów.

  1. Utwórz tabelę tymczasową i wstaw elementy listy (10 k). Następnie wykonaj połączenie z główną tabelą (1 zapytanie) i uzyskaj wyniki.

  2. Utwórz procedurę przechowywaną, aby pobrać listę pozycji (za pomocą tabeli zagnieżdżonej) jako zestaw danych wejściowych i wyników zwracanych za pośrednictwem parametru out.

Wybrałbym opcję 1. ponieważ jest prostsza dla mnie i prawdopodobnie szybsza. Ale musisz uważać na równoległe sesje itp. Nie wiesz, jak chcesz obsługiwać wiele sesji (czy będą udostępniać te dane, czy będą mieć oddzielne listy danych?).

Coś do rozważenia w każdym razie.

+1

Dzięki globalnej tabeli tymczasowej, Oracle obsługuje dla ciebie współbieżność (każda sesja ma swoją własną pustą tabelę na początek). –

0

To drobnostka, ale jeśli zamierzasz konstruować zapytanie dynamicznie (bez użycia zmiennych wiążących), powinieneś użyć createStatement, a nie prepareStatement. Jest niewielka ilość narzutów z przygotowaniem, którego nie potrzebujesz.

1

Możesz spróbować czegoś z klauzulą: sheetId IN ('1', '2', '3', '4') Upewnij się, że kolumna sheetId ma klucz indeksu.

Powiązane problemy