![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 555 Pomógł: 84 Dołączył: 20.02.2008 Skąd: Małopolska Ostrzeżenie: (0%) ![]() ![]() |
W taki sposób losuję, które rekordy z bazy danych mają być pobrane
Kod $comrades = $db -> Execute("SELECT * FROM users WHERE id >= ".$sektor_id -> fields['id']." AND id <= ".$sektor_id -> fields['id']." + 2 ORDER BY rand() LIMIT 4"); Niestety ilość rekordów spełniających te kryteria wynosi 3, a LIMIT 4. W jaki sposób przerobić to by było to prawdziwe losowanie - tj. za każdym razem byłby losowany user z podanego przedziału id bez względu na poprzednie losowania (czyt. możliwe byłoby pobranie kilka razy tego samego usera). |
|
|
![]() |
![]()
Post
#2
|
|
Grupa: Zarejestrowani Postów: 555 Pomógł: 84 Dołączył: 20.02.2008 Skąd: Małopolska Ostrzeżenie: (0%) ![]() ![]() |
Tylko teraz powstaje pytanie co jest bardziej wydajne i co mniej obciąży MySQL - Jeden z Twoich sposobów czy prosta funkcja while () zastosowana w PHP, losująca po 1 wyniku i dodająca ten wynik do tablicy?
|
|
|
![]()
Post
#3
|
|
Grupa: Zarejestrowani Postów: 60 Pomógł: 5 Dołączył: 28.08.2008 Ostrzeżenie: (0%) ![]() ![]() |
Tylko teraz powstaje pytanie co jest bardziej wydajne i co mniej obciąży MySQL - Jeden z Twoich sposobów czy prosta funkcja while () zastosowana w PHP, losująca po 1 wyniku i dodająca ten wynik do tablicy? Jak pisałem na początku mojego posta, wylosowanie jednego usera taką "prostą funkcją" trwa na mojej tabelce ok 10 seknud. Razy ilość userów do wylosowania... odpowiedź oczywista co bardziej wydajne ;) Aczkolwiek może to się da jeszcze przyspieszyć stosując w szukaj1/szukaj2 Dynamic SQL... ---- edit Poniżej wersja losująca unikalnych użytkowników. Stanowi ona wydajniejszą alternatywę dla zapytania w stylu:
pod warunkiem, że tabela xxx jest duża (rzędu 100 000 rekordów), a wybieramy losowo małą ich ilość np. 500. Dla przykładu zapytanie (a) z limitem 1 dla bazy o 262885 trwało 1.20 sec podczas gdy (b) losuj2uniq(1) trwało 0.01 sec. Dla limitu 100 mamy: (a) 2.46 sec, (b) 0.11; 500: (a) 1.18, (b)0.72 ;ale już dla limit 1000: (a) 1.22 (b) 1.84 Kod DROP PROCEDURE IF EXISTS losuj2uniq;
delimiter // CREATE PROCEDURE losuj2uniq( IN ileLosowac INT UNSIGNED) BEGIN -- użytkownik o najwyższym ID DECLARE maxId INT UNSIGNED; DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' BEGIN SET ileLosowac = ileLosowac+1; END; -- tabelka przechowująca wylosowane identyfikatory DROP TEMPORARY TABLE IF EXISTS numbers; CREATE TEMPORARY TABLE numbers (`user_id` int unsigned not null primary key) ENGINE=MEMORY; -- znajdź największy ID użytkownika SELECT MAX(`user_id`) FROM xxx INTO maxId; -- powtarzaj tyle razy, ile chcemy wyników losowanieUsera: WHILE ileLosowac > 0 DO BEGIN DECLARE randomElement INT UNSIGNED; SELECT FLOOR( 1+ RAND()*maxId ) INTO randomElement; -- Dodaj do tabelki pierwszego usera o ID równym wylosowanemu (może takiego nie być!) INSERT INTO numbers SELECT `user_id` FROM xxx WHERE `user_id`=randomElement LIMIT 1; -- Jeśli nie ma usera o takim ID, losujemy jeszcze raz IF ROW_COUNT()=0 THEN ITERATE losowanieUsera; END IF; -- Wylosowaliśmy kolejnego usera :) Zmniejsz ilość pzostałych do wylosowania SET ileLosowac = ileLosowac-1; END; END WHILE; -- Zwróć wylosowanych userów (zachowaj kolejność losowania) select xxx.user_id from numbers left join xxx on xxx.user_id=numbers.user_id; -- Jeśli kolejność nie ma znaczenia (w kolejności w jakiej są zapisani userzy) można użyć -- select * from numbers natural join xxx; -- Posprzątaj DROP TEMPORARY TABLE IF EXISTS numbers; END; // delimiter; Ten post edytował szopen 1.09.2008, 15:45:51 |
|
|
![]() ![]() |
![]() |
Aktualny czas: 14.10.2025 - 10:55 |