Saya punya tabel SQL Server dengan sekitar 50.000 baris di dalamnya. Saya ingin memilih sekitar 5.000 baris itu secara acak. Saya telah memikirkan cara yang rumit, membuat tabel temp dengan kolom "angka acak", menyalin tabel saya ke dalamnya, memutar melalui tabel temp dan memperbarui setiap baris dengan RAND()
, dan kemudian memilih dari tabel itu di mana kolom angka acak < 0,1. Saya mencari cara yang lebih sederhana untuk melakukannya, dalam satu pernyataan jika memungkinkan.
Artikel ini menyarankan untuk menggunakan NEWID()
fungsi ini. Itu terlihat menjanjikan, tetapi saya tidak bisa melihat bagaimana saya dapat memilih persentase baris dengan andal.
Adakah yang pernah melakukan ini sebelumnya? Ada ide?
sql
sql-server
random
John M Gant
sumber
sumber
Jawaban:
Menanggapi komentar "sampah murni" tentang tabel besar: Anda bisa melakukannya seperti ini untuk meningkatkan kinerja.
Biaya ini akan menjadi pemindaian kunci nilai plus biaya bergabung, yang pada tabel besar dengan pemilihan persentase kecil harus masuk akal.
sumber
[yourPk]
? EDIT: Nvm, berhasil ... Kunci Utama. Durrrnewid()
Sort Estimasi Biaya I / O akan sangat tinggi dan akan mempengaruhi kinerja.Tergantung pada kebutuhan Anda, Anda
TABLESAMPLE
akan mendapatkan kinerja yang hampir sama acak dan lebih baik. ini tersedia di MS SQL server 2005 dan yang lebih baru.TABLESAMPLE
akan mengembalikan data dari halaman acak alih-alih baris acak dan karenanya deos bahkan tidak mengambil data yang tidak akan kembali.Di atas meja yang sangat besar saya uji
butuh lebih dari 20 menit.
butuh 2 menit.
Kinerja juga akan meningkat pada sampel yang lebih kecil
TABLESAMPLE
padahal tidaknewid()
.Harap diingat bahwa ini tidak acak seperti
newid()
metode ini tetapi akan memberi Anda sampling yang layak.Lihat halaman MSDN .
sumber
newid () / order by akan bekerja, tetapi akan sangat mahal untuk set hasil besar karena harus menghasilkan id untuk setiap baris, dan kemudian mengurutkannya.
TABLESAMPLE () bagus dari sudut pandang kinerja, tetapi Anda akan mendapatkan hasil yang berkelompok (semua baris pada halaman akan dikembalikan).
Untuk sampel acak benar yang berkinerja lebih baik, cara terbaik adalah menyaring baris secara acak. Saya menemukan contoh kode berikut dalam artikel SQL Server Books Online yang Membatasi Set Hasil dengan Menggunakan TABLESAMPLE :
Saat dijalankan melawan tabel dengan 1.000.000 baris, berikut ini adalah hasil saya:
Jika Anda bisa menggunakan TABLESAMPLE, itu akan memberi Anda kinerja terbaik. Kalau tidak, gunakan metode newid () / filter. newid () / order oleh harus menjadi pilihan terakhir jika Anda memiliki hasil yang besar.
sumber
NewID()
hanya dievaluasi sekali, bukan per baris, yang saya tidak suka ...Memilih Baris Secara Acak dari Tabel Besar di MSDN memiliki solusi sederhana yang diartikulasikan dengan baik yang mengatasi masalah kinerja skala besar.
sumber
RAND()
tidak mengembalikan nilai yang sama untuk setiap baris (yang akan mengalahkanBINARY_CHECKSUM()
logika). Apakah itu karena itu disebut di dalam fungsi lain daripada menjadi bagian dari klausa SELECT?rand()
atau kombinasi di atas - tetapi saya berpaling dari solusi ini karena alasan itu. Juga jumlah hasil bervariasi dari 1 hingga 5 jadi ini mungkin juga tidak dapat diterima dalam beberapa skenario.RAND()
mengembalikan nilai yang sama untuk setiap baris (itulah sebabnya solusi ini cepat). Namun, baris dengan checksum biner yang sangat berdekatan memiliki risiko tinggi untuk menghasilkan hasil checksum yang serupa, menyebabkan penggumpalan ketikaRAND()
kecil. Misalnya,(ABS(CAST((BINARY_CHECKSUM(111,null,null) * 0.1) as int))) % 100
==SELECT (ABS(CAST((BINARY_CHECKSUM(113,null,null) * 0.1) as int))) % 100
. Jika data Anda menderita masalah ini, kalikanBINARY_CHECKSUM
dengan 9923.Tautan ini memiliki perbandingan yang menarik antara Orderby (NEWID ()) dan metode lain untuk tabel dengan 1, 7, dan 13 juta baris.
Seringkali, ketika pertanyaan tentang bagaimana memilih baris acak ditanyakan dalam kelompok diskusi, permintaan NEWID diajukan; itu sederhana dan bekerja sangat baik untuk meja kecil.
Namun, kueri NEWID memiliki kelemahan besar ketika Anda menggunakannya untuk tabel besar. Klausa ORDER BY menyebabkan semua baris dalam tabel untuk disalin ke database tempdb, di mana mereka diurutkan. Ini menyebabkan dua masalah:
Yang Anda butuhkan adalah cara untuk memilih baris secara acak yang tidak akan menggunakan tempdb dan tidak akan menjadi lebih lambat karena tabel semakin besar. Berikut adalah ide baru tentang cara melakukannya:
Gagasan dasar di balik kueri ini adalah bahwa kami ingin menghasilkan angka acak antara 0 dan 99 untuk setiap baris dalam tabel, dan lalu memilih semua baris yang angka acaknya kurang dari nilai persen yang ditentukan. Dalam contoh ini, kami ingin sekitar 10 persen dari baris dipilih secara acak; oleh karena itu, kami memilih semua baris yang nomor acaknya kurang dari 10.
Silakan baca artikel selengkapnya di MSDN .
sumber
Jika Anda (tidak seperti OP) membutuhkan sejumlah catatan tertentu (yang membuat pendekatan CHECKSUM sulit) dan menginginkan sampel yang lebih acak daripada yang disediakan oleh TABLESAMPLE sendiri, dan juga menginginkan kecepatan yang lebih baik daripada CHECKSUM, Anda dapat melakukan penggabungan dengan Metode TABLESAMPLE dan NEWID (), seperti ini:
Dalam kasus saya ini adalah kompromi paling langsung antara keacakan (itu tidak benar-benar, saya tahu) dan kecepatan. Variasikan TABLESAMPLE persentase (atau baris) yang sesuai - semakin tinggi persentase, semakin acak sampel, tetapi mengharapkan penurunan linear dalam kecepatan. (Perhatikan bahwa TABLESAMPLE tidak akan menerima variabel)
sumber
Cukup pesan tabel dengan nomor acak dan dapatkan 5.000 baris pertama menggunakan
TOP
.MEMPERBARUI
Hanya mencobanya dan
newid()
panggilan sudah cukup - tidak perlu untuk semua pemain dan semua matematika.sumber
Ini adalah kombinasi dari ide benih awal dan sebuah checksum, yang bagi saya memberikan hasil acak yang benar tanpa biaya NEWID ():
sumber
Di MySQL Anda dapat melakukan ini:
sumber
Belum melihat variasi ini dalam jawaban. Saya memiliki kendala tambahan di mana saya perlu, diberikan benih awal, untuk memilih set baris yang sama setiap kali.
Untuk MS SQL:
Contoh minimum:
Waktu pelaksanaan normal: 1,00
Contoh NewId ():
Waktu pelaksanaan normal: 1.02
NewId()
lebih lambat dari biasanyarand(checksum(*))
, jadi Anda mungkin tidak ingin menggunakannya melawan set rekaman besar.Pilihan dengan Benih Awal:
Jika Anda perlu memilih set yang sama dengan seed, ini sepertinya berhasil.
sumber
Coba ini:
sumber
Tampaknya newid () tidak dapat digunakan di mana klausa, jadi solusi ini memerlukan kueri batin:
sumber
Saya menggunakannya di subquery dan mengembalikan saya baris yang sama di subquery
maka saya diselesaikan dengan memasukkan variabel tabel induk di mana
Perhatikan kondisi di mana
sumber
Bahasa pemrosesan sisi server yang digunakan (misalnya PHP, .net, dll) tidak ditentukan, tetapi jika itu PHP, ambil nomor yang diperlukan (atau semua catatan) dan alih-alih mengacak dalam kueri gunakan fungsi acak PHP. Saya tidak tahu apakah .net memiliki fungsi yang setara tetapi jika tidak maka gunakan itu jika Anda menggunakan .net
ORDER BY RAND () dapat memiliki penalti kinerja yang cukup, tergantung pada berapa banyak catatan yang terlibat.
sumber
Ini bekerja untuk saya:
sumber
select top 10 percent from table_name order by rand()
, tetapi itu juga tidak berfungsi karena rand () mengembalikan nilai yang sama pada semua baris.