Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie kann ich zufällige Zeilen aus der Datenbank ausgeben?

Hier werden zwei Lösungen vorgestellt. Beide vorgeschlagenen Lösungen sind nur für MySQL und können von jeder Programmiersprache als Verbraucher verwendet werden. PHP wäre dafür viel zu langsam, aber es könnte der Konsument davon sein.

Schnellere Lösung :Ich kann 1000 zufällige Zeilen aus einer Tabelle mit 19 Millionen Zeilen in etwa 2 Zehntelsekunden mit fortgeschritteneren Programmiertechniken bringen.

Langsamere Lösung :Es dauert etwa 15 Sekunden mit Programmiertechniken ohne Stromversorgung.

Übrigens verwenden beide die Datengenerierung, die HIER zu sehen ist das ich geschrieben habe. Das ist also mein kleines Schema. Ich benutze das, weiter mit ZWEI mehr Selbstinserate dort drüben gesehen, bis ich 19M Zeilen habe. Also werde ich das nicht noch einmal zeigen. Aber um diese 19 Millionen Zeilen zu erhalten, sehen Sie sich das an und machen Sie zwei weitere dieser Einfügungen, und Sie haben 19 Millionen Zeilen.

Zuerst langsamere Version

Zuerst die langsamere Methode.

select id,thing from ratings order by rand() limit 1000;

Das gibt 1000 Zeilen in 15 Sekunden zurück.

Schnellere Lösung

Das ist etwas komplizierter zu beschreiben. Das Wesentliche dabei ist, dass Sie Ihre Zufallszahlen vorab berechnen und eine in clause generieren Ende von Zufallszahlen, durch Kommas getrennt und in Klammern eingeschlossen.

Es sieht aus wie (1,2,3,4) aber es wird 1000 Nummern enthalten.

Und Sie speichern sie und verwenden sie einmal. Wie ein One-Time-Pad für Kryptografie. Ok, keine großartige Analogie, aber ich hoffe, Sie verstehen, worauf es ankommt.

Betrachten Sie es als Ende für ein in -Klausel und in einer TEXT-Spalte gespeichert (wie ein Blob).

Warum um alles in der Welt sollte man das tun wollen? Weil RNG (Zufallszahlengeneratoren) sind unerschwinglich langsam. Aber sie mit ein paar Maschinen zu erzeugen, kann Tausende relativ schnell hervorbringen. Übrigens (und Sie werden dies in der Struktur meiner sogenannten Anhänge sehen, erfasse ich, wie lange es dauert, eine Zeile zu generieren. Etwa 1 Sekunde mit mysql. Aber C#, PHP, Java, alles kann das zusammenbringen. Der Punkt ist nicht, wie Sie es zusammenstellen, sondern dass Sie es haben, wann Sie es wollen.

Diese Strategie ist kurz und gut, wenn sie mit dem Abrufen einer Zeile kombiniert wird, die nicht als Zufallsliste verwendet wurde, sie als verwendet markiert und einen Aufruf wie

ausgibt
select id,thing from ratings where id in (a,b,c,d,e, ... )

und die in-Klausel 1000 Zahlen enthält, sind die Ergebnisse in weniger als einer halben Sekunde. verfügbar Effektiver Einsatz des mysql CBO (kostenbasierter Optimierer), als dass es wie ein Join auf einem PK-Index behandelt wird.

Ich belasse dies in zusammengefasster Form, weil es in der Praxis etwas kompliziert ist, enthält aber möglicherweise die folgenden Partikel

  • eine Tabelle mit den vorberechneten Zufallszahlen (Anhang A)
  • eine mysql create event-Strategie (Anhang B)
  • eine gespeicherte Prozedur, die eine vorbereitete Anweisung (Anhang C) verwendet
  • eine gespeicherte Prozedur nur für mysql, um RNG in zu demonstrieren Klausel für Kicks (Anhang D)

Anhang A

Eine Tabelle mit den vorberechneten Zufallszahlen

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
);

Anhang B

Um dies nicht in ein Buch zu verwandeln, siehe meine Antwort HIER für einen Mechanismus zum Ausführen eines wiederkehrenden mysql-Ereignisses. Es wird die Wartung der in Anhang A gezeigten Tabelle vorantreiben, indem es die in Anhang D gezeigten Techniken und andere Gedanken verwendet, die Sie sich ausdenken möchten. Wie Wiederverwendung von Zeilen, Archivieren, Löschen, was auch immer.

Anhang C

gespeicherte Prozedur, um mir einfach 1000 zufällige Zeilen zu liefern.

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 ;

Anhang D

Kann mit dem Konzept von Anhang B verflochten werden. Wie auch immer Sie es tun möchten. Aber es lässt Ihnen etwas übrig, um zu sehen, wie mysql es auf der RNG-Seite der Dinge ganz alleine machen könnte. Übrigens, wenn die Parameter 1 und 2 1000 bzw. 19M sind, dauert es auf meinem Rechner 800 ms.

Diese Routine könnte, wie eingangs erwähnt, in jeder beliebigen Sprache geschrieben werden.

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 ;

So rufen Sie die oben gespeicherte Prozedur auf:

call createARandomInString(1000,18000000);

Das generiert und speichert 1 Zeile mit 1000 Zahlen, die wie oben beschrieben umschlossen sind. Große Zahlen, 1 bis 18 Millionen

Als schnelle Veranschaulichung:Wenn man die gespeicherte Prozedur ändern würde, entferne die Zeile am unteren Rand, in der "used for debugging" steht, und habe diese als letzte Zeile in der gespeicherten proc, die ausgeführt wird, und führe Folgendes aus:

call createARandomInString(4,18000000);

... um 4 Zufallszahlen bis zu 18M zu generieren, könnten die Ergebnisse so aussehen

+-------------------------------------+
| myOutput                            |
+-------------------------------------+
| (2857561,5076608,16810360,14821977) |
+-------------------------------------+

Anhang E

Reality-Check. Dies sind etwas fortgeschrittene Techniken und ich kann niemanden darin unterrichten. Aber ich wollte sie trotzdem teilen. Aber ich kann es nicht lehren. Aus und vorbei.