Twee oplossingen die hier worden gepresenteerd. Beide voorgestelde oplossingen zijn alleen voor mysql en kunnen door elke programmeertaal als consument worden gebruikt. PHP zou hiervoor te traag zijn, maar het zou de consument ervan kunnen zijn.
Sneller oplossing :Ik kan 1000 willekeurige rijen uit een tabel van 19 miljoen rijen halen in ongeveer 2 tienden van een seconde met meer geavanceerde programmeertechnieken.
Langzamere oplossing :Het duurt ongeveer 15 seconden met programmeertechnieken zonder stroom.
Trouwens, beide gebruiken de gegevensgeneratie die wordt gezien HIER dat ik schreef. Dus dat is mijn kleine schema. Ik gebruik dat, ga verder met TWO meer zelf-inserts daar gezien, totdat ik 19 miljoen rijen heb. Dat ga ik dus niet nog een keer laten zien. Maar om die 19 miljoen rijen te krijgen, ga dat bekijken en doe nog 2 van die invoegingen, en je hebt 19 miljoen rijen.
Lagere versie eerst
Ten eerste de langzamere methode.
select id,thing from ratings order by rand() limit 1000;
Dat levert 1000 rijen op in 15 seconden.
Sneller oplossing
Dit is iets ingewikkelder om te beschrijven. De essentie is dat u uw willekeurige getallen vooraf berekent en een in clause
genereert einde willekeurige getallen, gescheiden door komma's en omwikkeld met een paar haakjes.
Het ziet eruit als (1,2,3,4)
maar het zal 1000 nummers bevatten.
En je slaat ze op en gebruikt ze eenmalig. Als een eenmalig pad voor cryptografie. Oké, geen geweldige analogie, maar ik hoop dat je het punt begrijpt.
Zie het als een einde voor een in
clausule, en opgeslagen in een TEXT-kolom (zoals een blob).
Waarom zou men dit in hemelsnaam willen doen? Omdat RNG (random number generators) zijn onbetaalbaar traag. Maar om ze met een paar machines te genereren, kunnen er relatief snel duizenden worden gegenereerd. Trouwens (en je zult dit zien in de structuur van mijn zogenaamde bijlagen, ik leg vast hoe lang het duurt om één rij te genereren. Ongeveer 1 seconde met mysql. Maar C#, PHP, Java, alles kan dat samenbrengen. Het punt is niet hoe je het in elkaar zet, maar dat je het hebt wanneer je het wilt.
Deze strategie, de lange en de korte ervan, is, wanneer dit wordt gecombineerd met het ophalen van een rij die niet als een willekeurige lijst is gebruikt, deze als gebruikt markeren en een oproep doen zoals
select id,thing from ratings where id in (a,b,c,d,e, ... )
en de in-clausule bevat 1000 cijfers, de resultaten zijn in minder dan een halve seconde beschikbaar. Effectief gebruik van de mysql CBO (cost based optimizer) dan behandelt het als een join op een PK-index.
Ik laat dit in beknopte vorm, omdat het in de praktijk een beetje ingewikkeld is, maar mogelijk de volgende deeltjes bevat
- een tabel met de vooraf berekende willekeurige getallen (bijlage A)
- een mysql create event-strategie (bijlage B)
- een opgeslagen procedure die werknemers een Opgemaakte Verklaring (Bijlage C)
- een mysql-only opgeslagen proc om RNG
in
te demonstreren clausule voor kicks (bijlage D)
Bijlage A
Een tabel met de vooraf berekende willekeurige getallen
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
);
Bijlage B
Om er geen boek van te maken, zie mijn antwoord HIER voor een mechanisme voor het uitvoeren van een terugkerend mysql-evenement. Het zal het onderhoud van de tabel in Bijlage A aansturen met behulp van technieken uit Bijlage D en andere gedachten die u wilt bedenken. Zoals hergebruik van rijen, archiveren, verwijderen, wat dan ook.
Bijlage C
opgeslagen procedure om me gewoon 1000 willekeurige rijen te bezorgen.
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 ;
Bijlage D
Kan worden verweven met het concept van bijlage B. Hoe je het ook wilt doen. Maar het laat je iets over om te zien hoe mysql het helemaal alleen zou kunnen doen aan de RNG-kant van de dingen. Trouwens, voor parameters 1 en 2 die respectievelijk 1000 en 19M zijn, duurt het 800 ms op mijn machine.
Deze routine kan in elke taal worden geschreven, zoals in het begin vermeld.
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 ;
Zo roept u de bovenstaande opgeslagen procedure op:
call createARandomInString(1000,18000000);
Dat genereert en bewaart 1 rij van 1000 nummers die zijn verpakt zoals hierboven beschreven. Grote aantallen, 1 tot 18 miljoen
Als een snelle illustratie, als men het opgeslagen proces zou wijzigen, verwijder dan de regel onderaan die zegt "gebruikt voor foutopsporing", en gebruik dat als de laatste regel in het opgeslagen proces dat wordt uitgevoerd, en voer dit uit:
call createARandomInString(4,18000000);
... om 4 willekeurige getallen tot 18M te genereren, kunnen de resultaten er als volgt uitzien:
+-------------------------------------+
| myOutput |
+-------------------------------------+
| (2857561,5076608,16810360,14821977) |
+-------------------------------------+
Bijlage E
Reality-check. Dit zijn enigszins geavanceerde technieken en ik kan er niemand bijles in geven. Maar ik wilde ze toch delen. Maar ik kan het niet aanleren. Over en uit.