Две решения, представени тук. И двете предложени решения са само за mysql и могат да се използват от всеки език за програмиране като потребител. PHP би бил твърде бавен за това, но може да е потребител на него.
По-бързо решение :Мога да изведа 1000 произволни реда от таблица от 19 милиона реда за около 2 десети от секундата с по-модерни техники за програмиране.
По-бавно решение :Отнема около 15 секунди с техники за програмиране без захранване.
Между другото и двете използват генерирането на данни, видяно ТУК което написах. Така че това е моята малка схема. Използвам това, продължете с ДВЕ повече самовмъквания се виждат там, докато имам 19 милиона реда. Така че няма да го показвам отново. Но за да получите тези 19 милиона реда, отидете да видите това и направете още 2 от тези вмъквания и ще имате 19 милиона реда.
Първо по-бавна версия
Първо, по-бавният метод.
select id,thing from ratings order by rand() limit 1000;
Това връща 1000 реда за 15 секунди.
По-бързо решение
Това е малко по-сложно за описание. Същността му е, че предварително изчислявате вашите произволни числа и генерирате in clause
край на произволни числа, разделени със запетаи и обвити с чифт скоби.
Ще изглежда като (1,2,3,4)
но в него ще има 1000 числа.
И вие ги съхранявате и ги използвайте веднъж. Като еднократна подложка за криптография. Добре, не е добра аналогия, но се надявам, че разбирате смисъла.
Мислете за това като за край на in
клауза и се съхранява в колона TEXT (като петно).
Защо, за Бога, човек би искал да направи това? Тъй като RNG (генератори на произволни числа) са изключително бавни. Но генерирането им с няколко машини може да бъде в състояние да изкара хиляди относително бързо. Между другото (и ще видите това в структурата на моите т.нар. приложения, аз улавям колко време отнема генерирането на един ред. Около 1 секунда с mysql. Но C#, PHP, Java, всичко може да събере това заедно. Въпросът не е как го сглобяваш, а че го имаш, когато го поискаш.
Тази стратегия, дългата и късата е, когато това се комбинира с извличане на ред, който не е бил използван като случаен списък, маркирането му като използван и издаване на повикване като
select id,thing from ratings where id in (a,b,c,d,e, ... )
и клаузата in има 1000 числа, резултатите са налични за по-малко от половин секунда. Ефективно използва mysql CBO (оптимизатор, базиран на разходите), отколкото го третира като присъединяване към PK индекс.
Оставям това в обобщен вид, защото е малко сложно на практика, но включва следните частици потенциално
- таблица, съдържаща предварително изчислените произволни числа (Приложение А)
- стратегия за създаване на събитие на mysql (Приложение Б)
- съхранена процедура, която използва подготвена декларация (Приложение В)
- съхранена само в mysql процедура за демонстриране на RNG
in
клауза за ритници (Приложение Г)
Допълнение A
Таблица, съдържаща предварително изчислените произволни числа
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
);
Приложение Б
В интерес да не превръщате това в книга, вижте моя отговор ТУК за механизъм за стартиране на повтарящо се mysql събитие. Той ще управлява поддръжката на таблицата, видяна в Приложение А, като използва техники, показани в Приложение D и други мисли, които искате да измислите. Като повторно използване на редове, архивиране, изтриване, каквото и да е.
Приложение В
съхранена процедура, за да ми даде просто 1000 произволни реда.
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 ;
Допълнение Г
Може да се преплита с концепцията на Приложение Б. Въпреки това искате да го направите. Но това ви оставя с нещо, за да видите как mysql може да направи всичко сам от страна на RNG на нещата. Между другото, за параметри 1 и 2, които са съответно 1000 и 19M, това отнема 800 ms на моята машина.
Тази рутина може да бъде написана на всеки език, както беше споменато в началото.
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 ;
Как да извикате горепосочената съхранена процедура:
call createARandomInString(1000,18000000);
Това генерира и записва 1 ред от 1000 числа, увити, както е описано по-горе. Големи числа, от 1 до 18 млн.
Като бърза илюстрация, ако някой трябва да промени съхранената процедура, премахнете отново реда близо до дъното, който казва „използва се за отстраняване на грешки“ и го задайте като последен ред в съхранения процес, който се изпълнява, и изпълнете това:
call createARandomInString(4,18000000);
... за генериране на 4 произволни числа до 18M, резултатите може да изглеждат така
+-------------------------------------+
| myOutput |
+-------------------------------------+
| (2857561,5076608,16810360,14821977) |
+-------------------------------------+
Приложение Е
Проверка на реалността. Това са малко напреднали техники и не мога да обучавам никого по тях. Но все пак исках да ги споделя. Но не мога да го науча. Отново и навън.