Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Bagaimana cara menggemakan baris acak dari database?

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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mysql hapus pesanan dengan

  2. 193:%1 bukan bug aplikasi Win32 yang valid dengan Aplikasi Rails baru

  3. Cara Mendapatkan Ukuran Tabel di MySQL

  4. FROM_UNIXTIME() Contoh – MySQL

  5. MySQL tidak akan membiarkan Login Pengguna:Kesalahan 1524