![]() |
![]() ![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 56 Pomógł: 0 Dołączył: 18.01.2009 Ostrzeżenie: (0%) ![]() ![]() |
Witam,
mam bazę 4 GB i chce pobrać losowy rekord spełniające moje kryteria. Teraz mam zastosowanie: Select pole FROM tabela WHERE pole='1' ORDER BY RAND(); LIMIT 1 Ale wykorzystując RAND() zapytanie trwa bardzo długo, przy dużych bazach nie spełnia roli. W jaki sposób wy wyciągacie losowe rekordy w takich dużych bazach? Z góry dziękuje za pomoc |
|
|
![]()
Post
#2
|
|
Grupa: Zarejestrowani Postów: 175 Pomógł: 30 Dołączył: 9.08.2007 Ostrzeżenie: (0%) ![]() ![]() |
Tutaj masz bardzo przydatny link: http://net.tutsplus.com/tutorials/other/to...best-practices/
Patrz punkt 6 odnośnie swojego pytania. |
|
|
![]()
Post
#3
|
|
Grupa: Zarejestrowani Postów: 56 Pomógł: 0 Dołączył: 18.01.2009 Ostrzeżenie: (0%) ![]() ![]() |
Tutaj masz bardzo przydatny link: http://net.tutsplus.com/tutorials/other/to...best-practices/ Patrz punkt 6 odnośnie swojego pytania. Hm... no jest to jakiś pomysł, ale jak dodam do pierwszego zapytanie Where, to całe zapytanie trwa 10 sekund troszkę dużo.. Wiadomo lepiej niż RAND, ale i ka długo... Może jeszcze jakieś pomysły> 10 sekund napisałem... Zapytanie z tego przykładu dostosowane do moich potrzeb trwa 100seknd |
|
|
![]()
Post
#4
|
|
![]() Grupa: Zarejestrowani Postów: 483 Pomógł: 50 Dołączył: 15.03.2005 Skąd: Poznań Ostrzeżenie: (0%) ![]() ![]() |
Aż mi sie nie chce wierzyć że:
wynik counta jak dasz w mt_rand() i pobierasz potem 1 rekord, daje ci 100 sekund geenrowania pracowałem na podobnej bazie wielkosciowo nie jeden raz i nigdy nie osiagnelem takiej "wartosci" zapytan Ten post edytował Hpsi+ 18.06.2011, 13:18:03 -------------------- Daiquiri: T1 = (dx/dt * s)^hpsi
Daiquiri: gdzie T1 - Twój czas przybycia na miejsce, dx/dt - prędkość, s droga Daiquiri: brb trzeba by to poprawić T1 - Czas jaki Ci to zajmie Daiquiri: Zatem T - czas dotarcia p T1 + T2 gdzie T2 = aktualny czas === po prostu kocham ją :D haha |
|
|
![]()
Post
#5
|
|
Grupa: Zarejestrowani Postów: 56 Pomógł: 0 Dołączył: 18.01.2009 Ostrzeżenie: (0%) ![]() ![]() |
Aż mi sie nie chce wierzyć że:
wynik counta jak dasz w mt_rand() i pobierasz potem 1 rekord, daje ci 100 sekund geenrowania pracowałem na podobnej bazie wielkosciowo nie jeden raz i nigdy nie osiagnelem takiej "wartosci" zapytan Tak, ale zobacz ze nie dodajesz przedrostka WHERE, a ja jeszcze dodatkowo daje regule do wyszukiwania. Baza ma 4 GB, i cały czas rośnie bo są tam dodawane rekordy ok 100MB na godzinę także wieczorem będzie 5 GB |
|
|
![]()
Post
#6
|
|
![]() Developer Grupa: Moderatorzy Postów: 3 045 Pomógł: 290 Dołączył: 20.01.2007 ![]() |
Aż mi sie nie chce wierzyć że:
wynik counta jak dasz w mt_rand() i pobierasz potem 1 rekord, daje ci 100 sekund geenrowania pracowałem na podobnej bazie wielkosciowo nie jeden raz i nigdy nie osiagnelem takiej "wartosci" zapytan Count zwróci Ci ilość rekordów. Wszystko będzie działać dobrze, o ile rekordy będą ponumerowane w odpowiedniej kolejności. Dla przykładu masz w bazie pięć rekordów (1, 2, 3, 5, 6). W takiej sytuacji mt_rand może wylosować Ci liczbę 4, co z wiadomej przyczyny nie zadziała. |
|
|
![]()
Post
#7
|
|
![]() Grupa: Zarejestrowani Postów: 651 Pomógł: 28 Dołączył: 4.12.2004 Ostrzeżenie: (0%) ![]() ![]() |
Możesz zrobić tak:
To zapytanie wylosuje jedną liczbę od 1 do N, gdzie N, to liczba rekordów w Twojej tabeli a następnie zwróci rekord o podanym ID. To rozwiązanie ma tą wadę, że jeśli rekordy są niespójne (nie ma ciągłości identyfikatorów ID) i część z nich jest usunięta, to wtedy zapytanie czasem zwróci pusty wynik (NULL). Można to spróbować jakoś rozwiązać w SQL-u, albo pójść na łatwiznę i w aplikacji webowej możesz zrobić pętlę do ... while, w której wykonasz to zapytanie raz jeszcze, gdy zwróci wartość NULL. Jeśli nieciągłość w identyfikatorach ID jest mała, rozwiązanie powinno się sprawdzić. Jeśli natomiast rozbieżność jest duża, może to działać bardzo wolno. Tak czy inaczej, powyższe zapytanie działa szybciej, niż ... ORDER BY RAND() choć jest mniej stabilne. Ten post edytował Speedy 18.06.2011, 14:55:28 -------------------- Sygnatura niezgodna z regulaminem.
|
|
|
![]()
Post
#8
|
|
![]() Grupa: Zarejestrowani Postów: 589 Pomógł: 91 Dołączył: 22.05.2008 Skąd: Gliwice Ostrzeżenie: (0%) ![]() ![]() |
Co Wy z tym WHERE id = xxx?
Przecież można:
@lysy2005 a masz na polu z którego robisz warunek dla COUNT zrobiony index? -------------------- Moja gra - scraby.io
|
|
|
![]()
Post
#9
|
|
Grupa: Zarejestrowani Postów: 56 Pomógł: 0 Dołączył: 18.01.2009 Ostrzeżenie: (0%) ![]() ![]() |
@lysy2005 a masz na polu z którego robisz warunek dla COUNT zrobiony index? Oczywiście, ale zapytanie miele i miele bo są cały czas dodawane nowe rekordy, zrobiłem tymczasowo że pobieram 1000 rekordów z warunkiem i z nim w phpie losuje randem. Sposób wskazany wyżej "count" nie zadziała bo dane nie są usegregowane po kolei, Id wygląda rak: 1,100,145,1111,456 itp, ponieważ czasami właśnie rekordy nie spełniające warunków są usuwane. Rozbudowałem troszkę skrypt i już dodaje 1GB na godzinę do bazy, baza ma 20GB wszystko zoptymalizowałem został ten rand nieszczęsny:( Ale 1GB danych na godzinę to trochę mało dla mnie, bo całość ma mieć 500GB... W takim tępię 20 dni by się robiło ;/ PS. może ktoś podpowie z konfiguracją my.cnf Serwer 6GB ramu ~9 GHz aktualnie mam zajęte 95% ramu. Wycinek najważniejszych ustawień: key_buffer = 80M max_allowed_packet = 80M thread_stack = 40M thread_cache_size = 6 query_cache_limit = 40M query_cache_size = 400M System Ubuntu 10, 64bit Baza jest w InnoDB Mysql Wersja serwera: 5.1.49-1ubuntu8.1 Z góry dzięki za pomoc! |
|
|
![]()
Post
#10
|
|
Grupa: Zarejestrowani Postów: 54 Pomógł: 12 Dołączył: 4.08.2007 Ostrzeżenie: (0%) ![]() ![]() |
Może rozbij tablice na kilkanaście mniejszych. Nie wiem jakie dane przechowujesz, ale np tablica1 mogłaby zawierać tylko wiersze z wartością pole 1 (albo 1 do 100,000, jeśli pole może przyjmować wartości od 1 do miliona).
|
|
|
![]()
Post
#11
|
|
![]() Grupa: Zarejestrowani Postów: 651 Pomógł: 28 Dołączył: 4.12.2004 Ostrzeżenie: (0%) ![]() ![]() |
Co Wy z tym WHERE id = xxx? Przecież można:
@lysy2005 a masz na polu z którego robisz warunek dla COUNT zrobiony index? Można tak, ale tego nie zrobisz w samym MySQL-u, ponieważ w klauzuli LIMIT nie można stosować zmiennych. Wymyśliłem inny sposób na rozwiązanie tego problemu, który jest pewną wariacją mojego poprzedniego pomysłu:
Zamiast dokładnego porównania ID do losowej wartości, wyszukujemy rekordy, które są większe lub równe, niż losowa wartość od 1 do N, gdzie N, to liczba wszystkich rekordów. Można też zmienić operator na znak mniejszości, ale wtedy zapytanie zawsze zwróci pierwszy wynik z tabeli, więc lepiej jest zrobić tak, jak napisałem wyżej. Wtedy nie musimy znajdować rekordu, który ma identyczny ID, jak losowy, ale znajdujemy więcej rekordów z danego zakresu i wybieramy pierwszy z nich. W takiej sytuacji zawsze wylosujemy jakiś rekord i zapytanie nigdy nie powinno zwrócić pustego wyniku. -------------------- Sygnatura niezgodna z regulaminem.
|
|
|
![]()
Post
#12
|
|
Grupa: Zarejestrowani Postów: 54 Pomógł: 12 Dołączył: 4.08.2007 Ostrzeżenie: (0%) ![]() ![]() |
Panowie, ale pamiętacie, że autor nie potrzebuje losowego wiersza z tabeli, tylko losowego wiersza spełniającego jakiśtam warunek?
|
|
|
![]()
Post
#13
|
|
![]() Grupa: Zarejestrowani Postów: 4 655 Pomógł: 556 Dołączył: 17.03.2009 Skąd: Katowice Ostrzeżenie: (0%) ![]() ![]() |
Fajnie jakbyś pokazał strukturę tej tabeli lub nawet tabel o ile są powiązane. Może da się to jakoś rozbić?
Swoją drogą co Ty przechowujesz w tej bazie, że w ciągu godziny o takie rozmiary się powiększa? -------------------- Zainteresowania: C#, PHP, JS, SQL, AJAX, XML, C dla AVR
Chętnie pomogę, lecz zanim napiszesz: Wujek Google , Manual PHP |
|
|
![]()
Post
#14
|
|
![]() Grupa: Zarejestrowani Postów: 651 Pomógł: 28 Dołączył: 4.12.2004 Ostrzeżenie: (0%) ![]() ![]() |
Panowie, ale pamiętacie, że autor nie potrzebuje losowego wiersza z tabeli, tylko losowego wiersza spełniającego jakiśtam warunek? Tylko nie wiadomo, co to za warunek, więc teraz mógłbym jedynie zgadywać (musiałbym mieć więcej szczegółów), ale rzeczywiście przy odpowiednim warunku moje ostatnie rozwiązanie może nie zadziałać zawsze. Jeżeli pominiemy ten warunek, rozwiązanie działa. -------------------- Sygnatura niezgodna z regulaminem.
|
|
|
![]()
Post
#15
|
|
![]() Grupa: Zarejestrowani Postów: 2 592 Pomógł: 445 Dołączył: 12.03.2007 Ostrzeżenie: (0%) ![]() ![]() |
Wybaczcie link do bloga, ale kiedyś o tym pisałem, przepisywanie z bloga nie ma sensu: MySQL RAND() – jak pobrać losowe wiersze
-------------------- |
|
|
![]()
Post
#16
|
|
Grupa: Zarejestrowani Postów: 54 Pomógł: 12 Dołączył: 4.08.2007 Ostrzeżenie: (0%) ![]() ![]() |
Wybaczcie link do bloga, ale kiedyś o tym pisałem, przepisywanie z bloga nie ma sensu: MySQL RAND() ? jak pobrać losowe wiersze Z tego co rozumiem proponujesz autorowi tworzenie tymczasowej tabeli zawierającej wszystkie id wierszy spełniających określony warunek WHERE? A następnie losowanie z tej tymczasowej tabeli id wiersza? I to wiedząc, że w ciągu godziny baza przybiera o 1GB? Czy może masz na myśli jakiś inny sposób podany na blogu? Ten post edytował aachi 19.06.2011, 21:16:08 |
|
|
![]()
Post
#17
|
|
![]() Grupa: Zarejestrowani Postów: 1 798 Pomógł: 307 Dołączył: 13.05.2009 Skąd: Gubin/Wrocław Ostrzeżenie: (0%) ![]() ![]() |
Dobrym rozwiązaniem byłoby zastosowanie cron'a, który powiedzmy co 10min mieliłby nawet bardzo skomplikowane zapytanie, z losowymi rekordami, ale większą ilością, powiedzmy 10k czy tam nawet 100k i zapisywał ich nie wiem, id, czy nawet całe wiersze, do pliku i potem odczytywać te 10k losowych rekordów i z tych 10k losowych rekordów wyciągać powiedzmy 20 losowych przy każdym requeście, które nam są potrzebne. Jakaś tam losowość pozostaje. Mysql akurat w przypadku tak dużej ilości danych nie jest dobrym rozwiązaniem. Do przechowywania dużej ilości danych dobre są bazy typu nosql, które lepiej sobie radzą z tak dużą ilością danych. Nie wiem jak mysql zachowa się powiedzmy przy 500gb danych. Radzę się zastanowić nad zmianą bazy.
|
|
|
![]()
Post
#18
|
|
Grupa: Zarejestrowani Postów: 207 Pomógł: 18 Dołączył: 4.09.2010 Skąd: warszawa Ostrzeżenie: (0%) ![]() ![]() |
coraz ciekawsze pomysły:
rozbijanie tabeli na wiele z powodu jednego zapytania? a reszta logiki aplikacji sama się dostosuje? 20GB to za dużo dla mysql? Autorze, moim skromnym zdaniem problem jest rozwiązywalny bez zmiany bazy Rzuć więcej info o samej bazie/tabeli/zapytaniach. opicy tego co robisz za pomocą php możesz sobie darować @all: no offence;) |
|
|
![]()
Post
#19
|
|
![]() Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
Ja osobiście kombinowałbym także pod kątem:
Zlicz ilość rekordów spełniających warunek, Wybierz liczbę od 0 do ilość-1 Zapytanie z WHERE oraz LIMIT wylosowana_liczba, 1. Omija się problem nieciągłości. Problemem jest jedynie szybka modyfikacja danych bazy, ale można to ominąć choćby funkcjami. -------------------- Najpierw był manual... Jeśli tam nie zawarto słów mądrości to zapytaj wszechwiedzącego Google zadając mu własciwe pytania. A jeśli i on milczy to Twój problem nie istnieje :D
|
|
|
![]()
Post
#20
|
|
![]() Grupa: Zarejestrowani Postów: 1 798 Pomógł: 307 Dołączył: 13.05.2009 Skąd: Gubin/Wrocław Ostrzeżenie: (0%) ![]() ![]() |
coraz ciekawsze pomysły: rozbijanie tabeli na wiele z powodu jednego zapytania? a reszta logiki aplikacji sama się dostosuje? 20GB to za dużo dla mysql? Autorze, moim skromnym zdaniem problem jest rozwiązywalny bez zmiany bazy Rzuć więcej info o samej bazie/tabeli/zapytaniach. opicy tego co robisz za pomocą php możesz sobie darować @all: no offence;) 20gb na mysql to nie jest za dużo, ale do składowania dużej ilości danych, używa się wyspecjalizowanych w tym kierunku baz danych, które radzą sobie o niebo lepiej, od średniego mysqla. |
|
|
![]() ![]() |
![]() |
Wersja Lo-Fi | Aktualny czas: 12.06.2025 - 16:09 |