Muszę napisać zapytanie, aby pobrać dużą listę identyfikatorów.
Obsługujemy wiele backendów (MySQL, Firebird, SQLServer, Oracle, PostgreSQL ...), więc muszę napisać standardowy SQL.
Rozmiar zestawu id mógłby być duży, zapytanie byłoby generowane programowo. Więc jakie jest najlepsze podejście?
1) Pisanie zapytania za pomocą IN
SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn)
Moje pytanie brzmi. Co się stanie, jeśli n jest bardzo duże? A co z wydajnością?
2) Pisanie zapytania przy użyciu OR
SELECT * FROM TABLE WHERE ID = id1 OR ID = id2 OR ... OR ID = idn
Myślę, że to podejście nie ma limitu n, ale co z wydajnością, jeśli n jest bardzo duże?
3) Pisanie rozwiązania programistycznego:
foreach (var id in myIdList)
{
var item = GetItemByQuery("SELECT * FROM TABLE WHERE ID = " + id);
myObjectList.Add(item);
}
Wystąpiły pewne problemy z tym podejściem, gdy serwer bazy danych był odpytywany przez sieć. Zwykle lepiej jest wykonać jedno zapytanie, które spowoduje pobranie wszystkich wyników, niż wykonanie wielu małych zapytań. Może się mylę.
Jakie byłoby prawidłowe rozwiązanie tego problemu?
IN
! Zrobiłem swoje jako twoje rozwiązanie 1 + 3. Tylko ostatnie zapytanie było jednym, długim ciągiem zapytania wysłanym do SQL w celu wykonania.Odpowiedzi:
Opcja 1 to jedyne dobre rozwiązanie.
Czemu?
Opcja 2 robi to samo, ale powtarzasz nazwę kolumny wiele razy; dodatkowo silnik SQL nie wie od razu, że chcesz sprawdzić, czy wartość jest jedną z wartości na ustalonej liście. Jednak dobry silnik SQL może go zoptymalizować, aby uzyskać taką samą wydajność jak w przypadku
IN
. Nadal jednak występuje problem z czytelnością ...Opcja 3 jest po prostu okropna pod względem wydajności. Wysyła zapytanie w każdej pętli i wbija bazę danych małymi zapytaniami. Zapobiega również stosowaniu jakichkolwiek optymalizacji dla „wartość jest jedną z tych na danej liście”
źródło
Alternatywnym podejściem może być użycie innej tabeli do przechowywania wartości id. Tę inną tabelę można następnie połączyć wewnętrznie w tabeli, aby ograniczyć zwracane wiersze. Będzie to miało tę główną zaletę, że nie będziesz potrzebować dynamicznego SQL (co jest problematyczne w najlepszym przypadku) i nie będziesz mieć nieskończenie długiej klauzuli IN.
Możesz obciąć tę drugą tabelę, wstawić dużą liczbę wierszy, a następnie prawdopodobnie utworzyć indeks, aby wspomóc wydajność łączenia. Pozwoliłoby to również oddzielić gromadzenie tych wierszy od pobierania danych, być może dając więcej opcji dostrajania wydajności.
Aktualizacja : Chociaż możesz użyć tabeli tymczasowej, nie chciałem sugerować, że musisz, a nawet powinieneś. Stała tabela używana do tymczasowych danych jest typowym rozwiązaniem, którego zalety wykraczają poza opisane tutaj.
źródło
select
instrukcji z innej tabeli. Lista jest przekazywana jako druga tabela,inner join
przeciwko której jesteś .To, co zasugerował Ed Guiness, jest naprawdę poprawiające wydajność, miałem takie pytanie
co ja zrobiłem :
Następnie wewnętrzna połączyła temp z głównym stołem:
Wydajność poprawiła się drastycznie.
źródło
Pierwsza opcja to zdecydowanie najlepsza opcja.
Biorąc jednak pod uwagę, że lista identyfikatorów jest bardzo duża , powiedzmy miliony, należy wziąć pod uwagę rozmiary fragmentów, jak poniżej:
Dlaczego należy dzielić na kawałki?
Zawsze działało na mnie jak urok. Mam nadzieję, że zadziała również dla moich kolegów programistów :)
źródło
Wykonanie polecenia SELECT * FROM MyTable where id in () na tabeli Azure SQL z 500 milionami rekordów skutkowało czasem oczekiwania> 7 minut!
Zamiast tego natychmiast zwróciło wyniki:
Użyj złączenia.
źródło
W większości systemów baz danych
IN (val1, val2, …)
i seriiOR
są zoptymalizowane do tego samego planu.Trzecim sposobem byłoby zaimportowanie listy wartości do tabeli tymczasowej i dołączenie do niej, co jest bardziej wydajne w większości systemów, jeśli jest dużo wartości.
Możesz przeczytać te artykuły:
źródło
Próbka 3 byłaby najgorsza ze wszystkich, ponieważ odwiedzasz bazę danych niezliczoną ilość razy bez wyraźnego powodu.
Załadowanie danych do tabeli tymczasowej, a następnie dołączenie do tego byłoby zdecydowanie najszybsze. Potem IN powinno działać nieco szybciej niż grupa OR.
źródło
Myślę, że masz na myśli SqlServer, ale w Oracle masz sztywny limit liczby elementów IN, które możesz określić: 1000.
źródło