Dua solusi disajikan di sini. Kedua solusi yang diusulkan ini hanya untuk mysql dan dapat digunakan oleh bahasa pemrograman apa pun sebagai konsumen. PHP akan sangat lambat untuk hal ini, tetapi bisa menjadi konsumennya.
Solusi Lebih Cepat :Saya dapat membawa 1000 baris acak dari tabel 19 juta baris dalam waktu sekitar 2 persepuluh detik dengan teknik pemrograman yang lebih maju.
Solusi Lebih Lambat :Dibutuhkan sekitar 15 detik dengan teknik pemrograman non-daya.
Omong-omong, keduanya menggunakan pembuatan data yang terlihat DI SINI yang saya tulis. Jadi itulah skema kecil saya. Saya menggunakan itu, lanjutkan dengan DUA lebih banyak sisipan diri terlihat di sana, sampai saya memiliki 19 juta baris. Jadi saya tidak akan menunjukkan itu lagi. Tetapi untuk mendapatkan 19 juta baris itu, lihat itu, dan lakukan 2 sisipan lagi, dan Anda memiliki 19 juta baris.
Lebih dulu versi yang lebih lambat
Pertama, metode yang lebih lambat.
select id,thing from ratings order by rand() limit 1000;
Itu mengembalikan 1000 baris dalam 15 detik.
Solusi lebih cepat
Ini sedikit lebih rumit untuk dijelaskan. Intinya adalah Anda menghitung terlebih dahulu angka acak Anda dan menghasilkan in clause
berakhir nomor acak, dipisahkan dengan koma, dan dibungkus dengan sepasang tanda kurung.
Ini akan terlihat seperti (1,2,3,4)
tapi itu akan memiliki 1000 nomor di dalamnya.
Dan Anda menyimpannya, dan menggunakannya sekali. Seperti papan satu waktu untuk kriptografi. Oke, bukan analogi yang bagus, tapi saya harap Anda mengerti maksudnya.
Anggap saja sebagai akhir dari in
klausa, dan disimpan dalam kolom TEXT (seperti gumpalan).
Mengapa di dunia orang ingin melakukan ini? Karena RNG (generator angka acak) sangat lambat. Tetapi untuk menghasilkannya dengan beberapa mesin mungkin dapat menghasilkan ribuan dengan relatif cepat. Omong-omong (dan Anda akan melihat ini dalam struktur lampiran saya yang disebut, saya menangkap berapa lama waktu yang dibutuhkan untuk menghasilkan satu baris. Sekitar 1 detik dengan mysql. Tapi C#, PHP, Java, apa pun bisa menyatukannya. Intinya bukan bagaimana Anda menyatukannya, melainkan bagaimana Anda memilikinya saat Anda menginginkannya.
Strategi ini, panjang dan pendeknya, ketika ini dikombinasikan dengan mengambil baris yang belum digunakan sebagai daftar acak, menandainya sebagai digunakan, dan mengeluarkan panggilan seperti
select id,thing from ratings where id in (a,b,c,d,e, ... )
dan klausa in memiliki 1000 angka di dalamnya, hasilnya tersedia dalam waktu kurang dari setengah detik. Efektif menggunakan CBO mysql (pengoptimal berbasis biaya) daripada memperlakukannya seperti bergabung pada indeks PK.
Saya meninggalkan ini dalam bentuk ringkasan, karena praktiknya agak rumit, tetapi berpotensi menyertakan partikel berikut
- tabel yang berisi bilangan acak yang telah dihitung sebelumnya (Lampiran A)
- strategi kejadian pembuatan mysql (Lampiran B)
- prosedur tersimpan yang menyediakan Pernyataan yang Disiapkan bagi karyawan (Lampiran C)
- proc yang disimpan hanya-mysql untuk mendemonstrasikan RNG
in
klausa untuk tendangan (Lampiran D)
Lampiran A
Tabel yang berisi angka acak yang telah dihitung sebelumnya
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
);
Lampiran B
Agar tidak mengubahnya menjadi buku, lihat jawaban saya DI SINI untuk mekanisme menjalankan Acara mysql berulang. Ini akan mendorong pemeliharaan tabel yang terlihat di Lampiran A menggunakan teknik yang terlihat di Lampiran D dan pemikiran lain yang ingin Anda impikan. Seperti penggunaan kembali baris, pengarsipan, penghapusan, apa pun.
Lampiran C
prosedur tersimpan untuk memberi saya 1000 baris acak.
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 ;
Lampiran D
Dapat dikaitkan dengan konsep Lampiran B. Bagaimanapun Anda ingin melakukannya. Tapi itu memberi Anda sesuatu untuk melihat bagaimana mysql bisa melakukan semuanya dengan sendirinya di sisi RNG. Omong-omong, untuk parameter 1 dan 2 masing-masing adalah 1000 dan 19M, dibutuhkan 800 mdtk di mesin saya.
Rutinitas ini dapat ditulis dalam bahasa apa pun seperti yang disebutkan di awal.
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 ;
Cara memanggil proc tersimpan di atas:
call createARandomInString(1000,18000000);
Itu menghasilkan dan menyimpan 1 baris, dari 1000 angka yang dibungkus seperti dijelaskan di atas. Angka besar, 1 hingga 18 juta
Sebagai ilustrasi singkat, jika seseorang ingin memodifikasi proc yang disimpan, hapus baris di dekat bagian bawah yang mengatakan "digunakan untuk debugging", dan jadikan itu sebagai baris terakhir, di proc tersimpan yang berjalan, dan jalankan ini:
call createARandomInString(4,18000000);
... untuk menghasilkan 4 angka acak hingga 18 juta, hasilnya mungkin terlihat seperti
+-------------------------------------+
| myOutput |
+-------------------------------------+
| (2857561,5076608,16810360,14821977) |
+-------------------------------------+
Lampiran E
Pengecekan kenyataan. Ini adalah teknik yang agak canggih dan saya tidak bisa mengajari siapa pun tentangnya. Tapi saya tetap ingin membaginya. Tapi saya tidak bisa mengajarkannya. Berulang kali.