Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak echo losowych wierszy z bazy danych?

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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak ustawić hasło roota na null?

  2. Jak działa funkcja SUBSTR() w MySQL

  3. Mysql - Pomóż mi zmienić to zapytanie, aby uzyskać pożądane wyniki

  4. MySQL Usuń zduplikowane wiersze, które mają tę samą wartość kolumny

  5. MySQL łączy wiele do wielu w jednym rzędzie