Przedstawione tutaj dwa rozwiązania. Oba te proponowane rozwiązania dotyczą tylko mysql i mogą być używane przez dowolny język programowania jako konsument. PHP byłby na to szalenie za wolny, ale może być jego konsumentem.
Szybsze rozwiązanie :Mogę pobrać 1000 losowych wierszy z tabeli zawierającej 19 milionów wierszy w około 2 dziesiąte sekundy dzięki bardziej zaawansowanym technikom programowania.
Wolniejsze rozwiązanie :Zajmuje to około 15 sekund w przypadku technik programowania bez zasilania.
Nawiasem mówiąc, obaj korzystają z generowania danych, które można zobaczyć TUTAJ które napisałem. To jest mój mały schemat. Używam tego, kontynuuj od DWA więcej samo-wstawek widać tam, aż mam 19 milionów rzędów. Więc nie zamierzam tego ponownie pokazywać. Ale aby uzyskać te 19 mln wierszy, zobacz to i wykonaj jeszcze 2 takie wstawki, a otrzymasz 19 mln wierszy.
Najpierw wolniejsza wersja
Po pierwsze wolniejsza metoda.
select id,thing from ratings order by rand() limit 1000;
To zwraca 1000 wierszy w 15 sekund.
Szybsze rozwiązanie
To jest trochę bardziej skomplikowane do opisania. Istotą tego jest to, że wstępnie obliczasz swoje liczby losowe i generujesz klauzulę in clause
zakończenie losowych liczb, oddzielonych przecinkami i owiniętych parą nawiasów.
Będzie wyglądać jak (1,2,3,4)
ale będzie zawierać 1000 numerów.
A ty je przechowujesz i używasz raz. Jak jednorazowy pad do kryptografii. Ok, nie jest to świetna analogia, ale mam nadzieję, że rozumiesz.
Pomyśl o tym jako o zakończeniu in clause
klauzuli i przechowywane w kolumnie TEKSTOWEJ (jak blob).
Dlaczego na świecie ktoś miałby chcieć to zrobić? Ponieważ RNG (generatory liczb losowych) są zbyt wolne. Ale wygenerowanie ich za pomocą kilku maszyn może być w stanie stosunkowo szybko wygenerować tysiące. Przy okazji (zobaczysz to w strukturze moich tak zwanych dodatków, przechwytuję, ile czasu zajmuje wygenerowanie jednego wiersza. Około 1 sekundy z mysql. Ale C#, PHP, Java, wszystko może to połączyć. Punkt nie jest tak, jak to składasz, a raczej, że masz to, kiedy chcesz.
Ta strategia, długa i krótka, jest połączona z pobraniem wiersza, który nie był używany jako lista losowa, oznaczeniem go jako używanego i wywołaniem, takim jak
select id,thing from ratings where id in (a,b,c,d,e, ... )
a klauzula in zawiera 1000 cyfr, wyniki są dostępne w mniej niż pół sekundy. Efektywne wykorzystanie mysql CBO (optymalizatora kosztów) niż traktowanie go jak złączenia w indeksie PK.
Zostawiam to w formie skróconej, ponieważ jest to trochę skomplikowane w praktyce, ale potencjalnie obejmuje następujące cząstki
- tabela zawierająca wstępnie obliczone liczby losowe (dodatek A)
- strategia tworzenia zdarzeń mysql (Załącznik B)
- procedura składowana, która wykorzystuje przygotowane oświadczenie (dodatek C)
- zapisany proces tylko w mysql, aby zademonstrować RNG
in
klauzula o kopnięciach (Załącznik D)
Załącznik A
Tabela zawierająca wstępnie obliczone liczby losowe
create table randomsToUse
( -- create a table of 1000 random numbers to use
-- format will be like a long "(a,b,c,d,e, ...)" string
-- pre-computed random numbers, fetched upon needed for use
id int auto_increment primary key,
used int not null, -- 0 = not used yet, 1= used
dtStartCreate datetime not null, -- next two lines to eyeball time spent generating this row
dtEndCreate datetime not null,
dtUsed datetime null, -- when was it used
txtInString text not null -- here is your in clause ending like (a,b,c,d,e, ... )
-- this may only have about 5000 rows and garbage cleaned
-- so maybe choose one or two more indexes, such as composites
);
Załącznik B
Aby nie zamienić tego w książkę, zobacz moją odpowiedź TUTAJ za mechanizm uruchamiania cyklicznego zdarzenia mysql. Będzie to prowadzić do utrzymania tabeli przedstawionej w Dodatku A przy użyciu technik z Dodatku D i innych myśli, które chcesz wymyślić. Takie jak ponowne wykorzystanie wierszy, archiwizacja, usuwanie, cokolwiek.
Załącznik C
procedura składowana, aby po prostu otrzymać 1000 losowych wierszy.
DROP PROCEDURE if exists showARandomChunk;
DELIMITER $$
CREATE PROCEDURE showARandomChunk
(
)
BEGIN
DECLARE i int;
DECLARE txtInClause text;
-- select now() into dtBegin;
select id,txtInString into i,txtInClause from randomsToUse where used=0 order by id limit 1;
-- select txtInClause as sOut; -- used for debugging
-- if I run this following statement, it is 19.9 seconds on my Dell laptop
-- with 19M rows
-- select * from ratings order by rand() limit 1000; -- 19 seconds
-- however, if I run the following "Prepared Statement", if takes 2 tenths of a second
-- for 1000 rows
set @s1=concat("select * from ratings where id in ",txtInClause);
PREPARE stmt1 FROM @s1;
EXECUTE stmt1; -- execute the puppy and give me 1000 rows
DEALLOCATE PREPARE stmt1;
END
$$
DELIMITER ;
Załącznik D
Może być powiązany z koncepcją Załącznika B. Jakkolwiek chcesz to zrobić. Ale pozostawia ci coś, aby zobaczyć, jak mysql może zrobić to wszystko sam po stronie RNG. Nawiasem mówiąc, dla parametrów 1 i 2 wynoszących odpowiednio 1000 i 19M zajmuje to 800 ms na moim komputerze.
Ta procedura może być napisana w dowolnym języku, jak wspomniano na początku.
drop procedure if exists createARandomInString;
DELIMITER $$
create procedure createARandomInString
( nHowMany int, -- how many numbers to you want
nMaxNum int -- max of any one number
)
BEGIN
DECLARE dtBegin datetime;
DECLARE dtEnd datetime;
DECLARE i int;
DECLARE txtInClause text;
select now() into dtBegin;
set i=1;
set txtInClause="(";
WHILE i<nHowMany DO
set txtInClause=concat(txtInClause,floor(rand()*nMaxNum)+1,", "); -- extra space good due to viewing in text editor
set i=i+1;
END WHILE;
set txtInClause=concat(txtInClause,floor(rand()*nMaxNum)+1,")");
-- select txtInClause as myOutput; -- used for debugging
select now() into dtEnd;
-- insert a row, that has not been used yet
insert randomsToUse(used,dtStartCreate,dtEndCreate,dtUsed,txtInString) values
(0,dtBegin,dtEnd,null,txtInClause);
END
$$
DELIMITER ;
Jak wywołać powyższą zapisaną procedurę:
call createARandomInString(1000,18000000);
To generuje i zapisuje 1 wiersz z 1000 liczb opakowanych w sposób opisany powyżej. Duże liczby, od 1 do 18 mln
Dla szybkiej ilustracji, jeśli ktoś miałby zmodyfikować przechowywany proces, usuń zremowanie wiersza na dole, który mówi „używane do debugowania”, i ustaw go jako ostatnią linię w przechowywanej procedurze, która działa, i uruchom to:
call createARandomInString(4,18000000);
... aby wygenerować 4 liczby losowe do 18 milionów, wyniki mogą wyglądać tak
+-------------------------------------+
| myOutput |
+-------------------------------------+
| (2857561,5076608,16810360,14821977) |
+-------------------------------------+
Załącznik E
Sprawdzenie autentyczności. Są to dość zaawansowane techniki i nie mogę nikogo z nich uczyć. Ale i tak chciałem się nimi podzielić. Ale nie mogę tego nauczyć. W kółko.