2009-10-07 19 views
47

Mam trzy tabele zdefiniować użytkowników:liczba MySQL elementów wewnątrz „w punkcie”

USER: user_id (int), username (varchar) 
USER_METADATA_FIELD: user_metadata_field_id (int), field_name (varchar) 
USER_METADATA: user_metadata_field_id (int), user_id (int), field_value (varchar) 

Chciałbym stworzyć środkowy użytkownikowi kondygnacji, która ma pewną dostęp do innych użytkowników w aplikacji. Aby określić, które użytkownicy zalogowanego użytku ma dostęp używam podkwerenda jak następuje:

SELECT user_id FROM user WHERE user_id 
    IN (SELECT user_id 
     FROM user_metadata 
     WHERE user_metadata_field_id = 1 AND field_value = 'foo') 

Obecnie jestem przechowywania ciąg podzapytanie w zmiennej, a następnie dynamicznie wkładając ją do zewnętrznej kwerendy za każdym razem muszę aby wyciągnąć listę użytkowników. Po zrobieniu tego pomyślałem: "lepiej będzie po prostu zapisać ciąg rzeczywistych user_id s".

Więc zamiast zapisywania tego w zmiennej ...

$subSql = "SELECT user_id FROM user_metadata WHERE user_metadata_field_id = 1 AND field_value = 'foo'"; 

... I faktycznie wykonywać kwerendy i zapisać wynik takiego ...

$subSql = "12, 56, 89, 100, 1234, 890"; 

wtedy kiedy muszę ciągnąć świeci użytkowników zalogowanych, że użytkownik ma dostęp do, mogę zrobić z:

$sql = "SELECT user_id FROM user WHERE user_id IN ($subSql)"; 

Na koniec pytania:

Ile elementów można użyć w KLAWISZE MySQL IN? Przechowywanie rzeczywistych identyfikatorów zamiast instrukcji sub-sql musi być szybsze przy wykonywaniu tego zapytania zewnętrznego za każdym razem, prawda?

Odpowiedz

33

Począwszy od pewnej liczby, tabele IN są szybsze.

MySQL ma coś w swoim kodzie, który sprawia, że ​​tworzenie zakresu przez dużą liczbę wartości stałych jest wolniejsze niż robienie tego samego w zagnieżdżonej pętli.

Zobacz artykuł w moim blogu o szczegóły wykonania:

+0

Hej Quassnoi: wydaje się, że jest wiele sporów dotyczących testów wydajności i stwierdzenie, że tymczasowy stół jest lepszy. Myślę, że możesz się mylić tutaj. – IcedDante

+1

@IcedDante: istnieją skrypty do odtworzenia wszystkiego, o czym pisałem w poście na blogu. Możesz napisać swój własny blog z własnymi skryptami i pokazać, jak bardzo się mylę. W przeciwnym razie takie rozmowy to tylko gorące powietrze. – Quassnoi

+0

Wiem, że to pytanie jest stare, ale twoja odpowiedź nie odpowiedziała na prawdziwe pytanie: "Ile pozycji możesz użyć w KLAWISZE MYSZY INS?" – Gusman

9

Jak zasugerował w odpowiedzi Quassnoi za jeden natyka innymi względami praktycznymi, przed trafienia ewentualne ograniczenie nałożonego przez daną implementację wersji MySql (*). Dlatego, ponieważ rośnie liczba użytkowników adminów (lub innych kryteriów, które mogą wymagać konstruktu IN), należy starać się używać alternatyw dla dosłownego "IN", na przykład korzystania z tymczasowych (lub nawet stałych) tabel.

Ponieważ rozważasz możliwość specjalnej obsługi kryteriów "administratora", dla celów wydajności chciałbym przedstawić komentarz i sugestię.

Komentarz: Czy może to być przypadek przedwczesnej optymalizacji?
Nie jestem świadomy specyfiki tej bazy danych, jej objętości, złożoności itd. I tak, mam świadomość, że należy się hołd wydajnościowy dla EAV (Entity-Attribute-Value), ale jestem myśląc, że nawet dla odnoszących sukcesy firm baza danych kont rzadko liczy ponad 10 000 użytkowników.Tak więc nawet przy bardzo wielu atrybutach na użytkownika nadal patrzymy na stosunkowo małą tabelę EAV, która może nie wymagać takiej optymalizacji. (Z drugiej strony kilka innych sztuczek optymalizacyjnych może być mile widzianych w innych obszarach).
Co więcej, typowe przypadki użycia obejmują stosunkowo niewiele zapytań w bazie danych kont, w stosunku do innych zapytań, i dlatego jest to kolejny powód, aby odrzucić wszelkie nietrywialne uwzględnienie wydajności dla funkcji związanych z kontami aplikacji.

Sugestia: Może użyć „Re-znormalizowane atrybuty”
Dla atrybutów, które są wyodrębnione wartościach, w szczególności jeśli są one krótkie, mogą być przemieszczane (lub powielane) w tabeli Entity („user” tabela w tym przypadku). Wprowadza to trochę logiki w momencie wstawiania lub aktualizowania elementów, ale ta sama liczba łączy (lub podzapytań), a także zapewnia możliwości uwzględnienia indeksów wielobazowych w celu obsługi najczęściej używanych przypadków.

(*) Czy istnieje ograniczenie?
Nie czytałem o takim limicie; Wiem, że Oracle ma (miał) 1000 limit w pewnym momencie, MSSQL nie; oczywiście wszystkie serwery mają limit na podstawie całkowitej długości instrukcji SQL, ale jest to naprawdę duża liczba! jeśli ktoś kiedykolwiek natknie się na to, ma inne problemy ... ;-)

4

Klauzula IN MySQL sama w sobie nie ma takiego limitu. Próbowałem z 8000 elementów, które dobrze sprawdziły się dla mnie. błąd przepełnienia stosu może być zmiennej zadeklarowanej,

117

Z manual:

Liczba wartości w liście IN jest ograniczona tylko przez wartość max_allowed_packet.

+10

Przykładem ustawienia domyślnego jest 'max_allowed_packet | 1048576' (1 MB) – icvg

+7

+1 za udzielenie odpowiedzi na pytanie. Dziękuję Ci. – Bryan

+1

[Domyślna wartość max_allowed_packet to 4MB] (http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_max_allowed_packet) –