Post
#1
|
|
|
Grupa: Zarejestrowani Postów: 124 Pomógł: 1 Dołączył: 13.07.2009 Ostrzeżenie: (0%)
|
Zna ktoś jakiś szybki sposób na wybranie 12 losowych rekordów z tabeli, która może mieć nawet kilka milionów wierszy? Do tego biorąc pod uwagę, że będzie bardzo często odczytywana.
Najpierw próbowałem tego: http://blog.desmart.com/2008/03/12/sposob-...-tablicy-mysql/ ale losuje mi 12 rekordów, tyle, że następujących po sobie jeden po drugim, czyli tak naprawdę losuje miejsce startowe, skąd ma pobrać kolejne rekordy. Nie umiem tego przerobić tak by wybrało 12 zupełnie przypadkowych rekordów. Pomyślałem więc, że wylosuję w PHP ok. 50 liczb, i używając ich zadam zapytanie:
Ale to mi nie daje gwarancji, że wybierze dokładnie 12 rekordów, bo przecież niektóre o podanych ID mogą nie istnieć. W sumie mogę tak wybierać rekordy aż uzyskam dokładnie 12 (bo to mała liczba) ale może zna ktoś jakiś lepszy sposób? |
|
|
|
![]() |
Post
#2
|
|
|
Grupa: Zarejestrowani Postów: 243 Pomógł: 20 Dołączył: 20.04.2004 Skąd: Wielkopolska Ostrzeżenie: (0%)
|
Kod SELECT * FROM tabela ORDER BY RAND() LIMIT 12
|
|
|
|
Post
#3
|
|
|
Grupa: Moderatorzy Postów: 36 561 Pomógł: 6315 Dołączył: 27.12.2004 |
@luki100011 zanim udzielisz jakze pomocnej odpowiedzi, przeczytaj najpierw co autor napisał...
W linku co podal metoda ta też jest podana. Jest też podane tam rownież dlaczego nalezy jej nie uzywac. Przeczytaj, wiedza ta moze ci sie przyda w przyszlosci |
|
|
|
Post
#4
|
|
|
Grupa: Moderatorzy Postów: 6 072 Pomógł: 861 Dołączył: 10.12.2003 Skąd: Dąbrowa Górnicza |
Może więc w PHP losuj 12 + X liczb, gdzie X to odpowiedni "zapas" jeśli danego artykuły by nie było. Następnie wybierasz rekordy z warunkiem IN (wylosowane_liczby) LIMIT 12. Jeśli dobierzesz odpowiednią wartość X (odpowiednio duża jeśli jest duże prawdopodobieństwo trafienia na "dziurę") to będziesz miał naprawdę pecha jeśli zapytanie nie zwróci Ci faktycznie 12 rekordów.
|
|
|
|
Post
#5
|
|
|
Grupa: Zarejestrowani Postów: 855 Pomógł: 145 Dołączył: 17.07.2008 Skąd: High Memory Area Ostrzeżenie: (0%)
|
http://www.slideshare.net/billkarwin/sql-a...rns-strike-back
Od slajdu 141. Solution #4 całkiem sprytne. |
|
|
|
Post
#6
|
|
|
Grupa: Moderatorzy Postów: 36 561 Pomógł: 6315 Dołączył: 27.12.2004 |
@Mchl Twoje rozwiązanie również pobiera 1 rekord.
|
|
|
|
Post
#7
|
|
|
Grupa: Moderatorzy Postów: 6 072 Pomógł: 861 Dołączył: 10.12.2003 Skąd: Dąbrowa Górnicza |
@Mchl:
Zgadza się, jest to dość sprytne rozwiązanie, ale w tym przypadku chyba nie do końca przypadnie autorowi do gustu. Jego minusem będzie to, że wybierze rekordy po kolei od zadanego (wylosowanego) punktu startowego. @nospor: Można przecież nadać ograniczenie, że liczba rekordów = rzeczywista liczba rekordów - limit i wtedy można pobrać X "losowych" rekordów. Ten post edytował phpion 22.04.2010, 13:06:57 |
|
|
|
Post
#8
|
|
|
Grupa: Zarejestrowani Postów: 855 Pomógł: 145 Dołączył: 17.07.2008 Skąd: High Memory Area Ostrzeżenie: (0%)
|
Jak zostosuje je dosłownie w takiej postaci jak przedstawiona to na pewno.
Ale kto mu broni wylosować 12 offsetów i złożyć przez UNION zapytanie 12 SELECTów? |
|
|
|
Post
#9
|
|
|
Grupa: Moderatorzy Postów: 6 072 Pomógł: 861 Dołączył: 10.12.2003 Skąd: Dąbrowa Górnicza |
No tak, ale dochodzi tutaj kwestia liczby wykonanych zapytań oraz możliwość powstawania powtórzeń w wylosowanych rekordach.
|
|
|
|
Post
#10
|
|
|
Grupa: Moderatorzy Postów: 36 561 Pomógł: 6315 Dołączył: 27.12.2004 |
Cytat Ale kto mu broni wylosować 12 offsetów i złożyć przez UNION zapytanie 12 SELECTów? Ba.... nikt mu nie zabroni. Ale to mogl zrobic juz na samym początku przy rozwiązaniu ktore sam podał. A weź pobierz 12 losowych rekordów bez union i bez 12 zapytan.... (IMG:style_emoticons/default/smile.gif)
|
|
|
|
Post
#11
|
|
|
Grupa: Zarejestrowani Postów: 855 Pomógł: 145 Dołączył: 17.07.2008 Skąd: High Memory Area Ostrzeżenie: (0%)
|
Kod SELECT COUNT(*) FROM test.t_option; > 2000000 Kod SELECT SQL_NO_CACHE * FROM test.t_option ORDER BY RAND() LIMIT 1; 2.1342s Kod SELECT SQL_NO_CACHE * FROM test.t_option LIMIT 1 OFFSET 653143; 0.3164s Ten post edytował Mchl 22.04.2010, 13:16:05 |
|
|
|
Post
#12
|
|
|
Grupa: Moderatorzy Postów: 36 561 Pomógł: 6315 Dołączył: 27.12.2004 |
No i czemu te zestawienie ma sluzyc? Przeciez to oczywiste. Ba... nawet jest podane w pierwszym linku w pierwszym poscie. Jak to ma sie do 12 losowych rekordów bez UNION i bez 12 zapytan? (IMG:style_emoticons/default/smile.gif)
|
|
|
|
Post
#13
|
|
|
Grupa: Zarejestrowani Postów: 855 Pomógł: 145 Dołączył: 17.07.2008 Skąd: High Memory Area Ostrzeżenie: (0%)
|
Ale dlaczego bez UNION? Skąd taki wymóg?
|
|
|
|
Post
#14
|
|
|
Grupa: Moderatorzy Postów: 36 561 Pomógł: 6315 Dołączył: 27.12.2004 |
oj... zmieniasz te fronty.. tu mi jakies wyniki, tu jakies zapytania i za kazdym razem unikasz odpowiedzi na pytanie (IMG:style_emoticons/default/winksmiley.jpg)
Cytat Ale dlaczego bez UNION? Skąd taki wymóg? zaden wymog. Wyjasniam ci jedynie ze UNION to on juz mogl uzyc na samym poczatku przy zapytaniu co podal. Zapytal sie jednak jak mozna to zrobic inaczej, a ty w odpowiedzi podales swoje zapytanie, inne, które tez pobiera jeden rekord. |
|
|
|
Post
#15
|
|
|
Grupa: Moderatorzy Postów: 6 072 Pomógł: 861 Dołączył: 10.12.2003 Skąd: Dąbrowa Górnicza |
Swoją drogą: czy przypadkiem rozwiązanie z IN (1, 2, 3) nie będzie przypadkiem szybsze? Przyznam, że wynik dla drugiego zapytania (0.3164s) jakoś szczególnie mnie nie powalił swą szybkością. Czy mógłbyś wykonać zapytanie z kilkoma identyfikatorami w IN?
|
|
|
|
Post
#16
|
|
|
Grupa: Moderatorzy Postów: 36 561 Pomógł: 6315 Dołączył: 27.12.2004 |
@phpion ale przeciez dla IN musisz podac np. konkretne ID. A o dziurach nie slyszal? (IMG:style_emoticons/default/winksmiley.jpg)
|
|
|
|
Post
#17
|
|
|
Grupa: Moderatorzy Postów: 6 072 Pomógł: 861 Dołączył: 10.12.2003 Skąd: Dąbrowa Górnicza |
@phpion ale przeciez dla IN musisz podac np. konkretne ID. A o dziurach nie slyszal? (IMG:style_emoticons/default/winksmiley.jpg) Może więc w PHP losuj 12 + X liczb, gdzie X to odpowiedni "zapas" jeśli danego artykuły by nie było. Następnie wybierasz rekordy z warunkiem IN (wylosowane_liczby) LIMIT 12. Jeśli dobierzesz odpowiednią wartość X (odpowiednio duża jeśli jest duże prawdopodobieństwo trafienia na "dziurę") to będziesz miał naprawdę pecha jeśli zapytanie nie zwróci Ci faktycznie 12 rekordów. (IMG:style_emoticons/default/party.gif) |
|
|
|
Post
#18
|
|
|
Grupa: Moderatorzy Postów: 36 561 Pomógł: 6315 Dołączył: 27.12.2004 |
ps: tak, czytalem twoje poprzednie posty o prawdopodobienstwu - nie podoba mi sie ta teoria (IMG:style_emoticons/default/winksmiley.jpg)
|
|
|
|
Post
#19
|
|
|
Grupa: Moderatorzy Postów: 6 072 Pomógł: 861 Dołączył: 10.12.2003 Skąd: Dąbrowa Górnicza |
No mi generalnie również nie do końca bo zawsze może się zdarzyć przypadek, gdy zapytanie zwróci 0 rekordów (wylosujemy same "dziury"). Jednak wybieranie rekordów po PK powinno być zdecydowanie szybsze niż wycinanie danego fragmentu ze zbioru - stąd moja prośba do Mchl o wykonanie zapytania i podanie wyniku.
|
|
|
|
Post
#20
|
|
|
Grupa: Zarejestrowani Postów: 855 Pomógł: 145 Dołączył: 17.07.2008 Skąd: High Memory Area Ostrzeżenie: (0%)
|
Wszystkie metody opierające się na losowaniu wartości klucza głównego zakłądają, że klucz główny jest ciągły.
Jeśli nie jest, to na przykład zapytanie podane w linku w pierwszym poście, raz na jakiś czas zwróci 0 wierszy. Czy to dopuszczalne? Pewnie jak się ma tego świadomość i dobrze obsłuży to tak. Jeżeli wywołanie pierwszego zapytania tyle razy żeby uzyskać dokładnie 12 wierszy będzie w 99,99% szybsze niż wywołanie 12 razy rozwiązania podanego przeze mnie, to chyba wiadomo jaki jest wybór. @phpion: niestety akurat ta tabela nie ma klucza głównego auto_increment, więc trudno byłoby zrobić porównanie. Niewątpliwie jednak, wybieranie po PK będzie szybsze. Pytanie tylko, jak często losując wartość PK trafiamy na wartość rzeczywiście istniejącą. Ten post edytował Mchl 22.04.2010, 13:30:32 |
|
|
|
![]() ![]() |
|
Aktualny czas: 22.12.2025 - 16:36 |