Giả sử cần lấy 10 bản ghi ngẫu nhiên để hiển thị thành 1 page trên website:
Sử dụng các câu truy vấn có sẵn
SQL SERVER
SELECT TOP 10 column FROM table ORDER BY NEWID()
MySQL
SELECT column FROM table ORDER BY RAND() LIMIT 10
Oracle
SELECT column FROM ( SELECT column FROM table ORDER BY dbms_random.value ) WHERE rownum <= 10
DB2
SELECT column, RAND() as IDX FROM table ORDER BY IDX FETCH FIRST 10 ROWS ONLY
PostgreSQL
SELECT column FROM table ORDER BY RANDOM() LIMIT 10
MongoDb
var count = db.coll.count(); var result = new Array(); for (var i=0; i<10; i++) { var idx = parseInt(Math.random() * count); var item = db.coll.find().skip(idx).limit(1).toArray()[0]; result.push(item); } printjson(result);
Tự cài đặt để lấy ngẫu nhiên
Với các câu lệnh SQL trên, ta thấy đều phải sử dụng sắp xếp theo một phần tử ngẫu nhiên rồi lấy top 10 bản ghi đầu. Việc sắp xếp này thường tốn kém nhiều tài nguyên – thường là O(nlog(n)) – nên nếu thực hiện nhiều có thể ảnh hưởng đến hiệu năng hệ thống. Ta có thể cài đặt việc lấy ngẫu nhiên như sau giúp việc tìm ngẫu nhiên 10 phần tử nhanh hơn:
- Bước 1: cứ khi thêm một phần tử, ta chèn thêm một số nguyên là idx được lấy tăng dần (trong sql là trường identity(1,1), trong oracle dùng sequence, mongodb thì sử dụng một collection để lưu trữ giá trị idx hiện tại này)
- Bước 2: đánh index trên trường idx này (giúp tìm kiếm nhanh hơn)
- Bước 3: tạo ra mảng 10 số ngẫu nhiên nằm trong khoảng [0, IDX)
- Bước 4: truy vấn ra các bản ghi có idx bằng các số trong mảng trên.
RDBMS: Sql Server, MySql, Oracle …
SELECT column FROM table WHERE idx in (r1, r2, r3, r4, r5, r6, r7, r8, r9, r10)
MongoDb
var IDX = db.coll.count(); var randomArray = new Array(); for (var i=0; i<10; i++) randomArray.push(parseInt(Math.random() * IDX)); var result = db.coll.find({idx: {$in: randomArray}}); printjson(result.toArray());
Với cách này, độ phức tạp chỉ là log(n).
Lưu ý:
Cách trên có thể khi chạy không ra đúng 10 kết quả nếu trong 10 số ngẫu nhiên rơi vào idx của bản ghi bị xóa. Do vậy kỹ thuật trên tốt đối với các bản ghi không bị xóa.