Hai giải pháp được trình bày ở đây. Cả hai giải pháp được đề xuất này đều chỉ dành cho mysql và có thể được sử dụng bởi bất kỳ ngôn ngữ lập trình nào với tư cách là người tiêu dùng. PHP sẽ thực sự quá chậm đối với điều này, nhưng nó có thể là người tiêu dùng của nó.
Giải pháp nhanh hơn :Tôi có thể mang đến 1000 hàng ngẫu nhiên từ một bảng gồm 19 triệu hàng trong khoảng 2 phần mười giây bằng các kỹ thuật lập trình nâng cao hơn.
Giải pháp chậm hơn :Mất khoảng 15 giây với các kỹ thuật lập trình không dùng điện.
Bằng cách này, cả hai đều sử dụng việc tạo dữ liệu đã thấy TẠI ĐÂY mà tôi đã viết. Vì vậy, đó là lược đồ nhỏ của tôi. Tôi sử dụng điều đó, tiếp tục với TWO nhiều tự chèn hơn được nhìn thấy ở đó, cho đến khi tôi có 19 triệu hàng. Vì vậy, tôi sẽ không hiển thị điều đó một lần nữa. Nhưng để có được 19 triệu hàng đó, hãy xem điều đó và thực hiện thêm 2 lần chèn nữa và bạn có 19 triệu hàng.
Phiên bản đầu tiên chậm hơn
Đầu tiên, phương pháp chậm hơn.
select id,thing from ratings order by rand() limit 1000;
Điều đó trả về 1000 hàng trong 15 giây.
Giải pháp nhanh hơn
Điều này phức tạp hơn một chút để mô tả. Ý chính của nó là bạn tính toán trước các số ngẫu nhiên của mình và tạo một in clause
kết thúc của các số ngẫu nhiên, được phân tách bằng dấu phẩy và được bao bọc bằng một cặp dấu ngoặc đơn.
Nó sẽ giống như (1,2,3,4)
nhưng nó sẽ có 1000 số trong đó.
Và bạn lưu trữ chúng, và sử dụng chúng một lần. Giống như một bảng thời gian cho mật mã. Được rồi, không phải là một sự so sánh tuyệt vời, nhưng bạn sẽ hiểu được điểm mà tôi hy vọng.
Hãy coi nó như một phần kết thúc cho một in
và được lưu trữ trong cột TEXT (như một đốm màu).
Tại sao trên thế giới người ta muốn làm điều này? Bởi vì RNG (trình tạo số ngẫu nhiên) rất chậm. Nhưng để tạo ra chúng với một vài máy có thể tạo ra hàng nghìn chiếc tương đối nhanh chóng. Nhân tiện (và bạn sẽ thấy điều này trong cấu trúc của cái gọi là phụ lục của tôi, tôi nắm bắt được mất bao lâu để tạo một hàng. Khoảng 1 giây với mysql. Nhưng C #, PHP, Java, mọi thứ đều có thể kết hợp điều đó lại với nhau. Điểm không phải là cách bạn đặt nó lại với nhau, mà là bạn có nó khi bạn muốn.
Chiến lược này, dài và ngắn, khi điều này được kết hợp với việc tìm nạp một hàng chưa được sử dụng làm danh sách ngẫu nhiên, đánh dấu hàng đó là đã sử dụng và đưa ra lệnh gọi, chẳng hạn như
select id,thing from ratings where id in (a,b,c,d,e, ... )
và mệnh đề in có 1000 số, kết quả có sẵn sau chưa đầy nửa giây. Sử dụng mysql CBO (trình tối ưu hóa dựa trên chi phí) hiệu quả hơn so với xử lý nó như một kết hợp trên chỉ số PK.
Tôi để điều này ở dạng tóm tắt, vì nó hơi phức tạp trong thực tế, nhưng có thể bao gồm các phần tử sau đây
- một bảng chứa các số ngẫu nhiên được tính toán trước (Phụ lục A)
- một chiến lược tạo sự kiện mysql (Phụ lục B)
- một thủ tục được lưu trữ mà nhân viên của một Tuyên bố Chuẩn bị (Phụ lục C)
- một proc chỉ được lưu trữ trong mysql để chứng minh RNG
in
điều khoản cho các cú đá (Phụ lục D)
Phụ lục A
Một bảng chứa các số ngẫu nhiên được tính toán trước
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
);
Phụ lục B
Vì lợi ích của việc không biến nó thành sách, hãy xem câu trả lời của tôi TẠI ĐÂY để biết cơ chế chạy Sự kiện mysql định kỳ. Nó sẽ thúc đẩy việc duy trì bảng trong Phụ lục A bằng cách sử dụng các kỹ thuật trong Phụ lục D và những suy nghĩ khác mà bạn muốn mơ ước. Chẳng hạn như sử dụng lại các hàng, lưu trữ, xóa, bất cứ điều gì.
Phụ lục C
thủ tục được lưu trữ để giúp tôi có được 1000 hàng ngẫu nhiên.
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 ;
Phụ lục D
Có thể đan xen với khái niệm Phụ lục B. Tuy nhiên bạn muốn làm điều đó. Nhưng nó để lại cho bạn một điều gì đó để xem cách mysql có thể tự mình làm điều đó ở khía cạnh RNG của mọi thứ. Nhân tiện, đối với thông số 1 và 2 lần lượt là 1000 và 19M, máy của tôi mất 800 mili giây.
Quy trình này có thể được viết bằng bất kỳ ngôn ngữ nào như đã đề cập ở phần đầu.
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 ;
Cách gọi proc được lưu trữ ở trên:
call createARandomInString(1000,18000000);
Điều đó tạo ra và lưu 1 hàng, trong số 1000 số được bao bọc như mô tả ở trên. Số lớn, 1 đến 18 triệu
Như một minh họa nhanh, nếu một người sửa đổi proc đã lưu trữ, hãy bỏ rem dòng gần cuối có nội dung "được sử dụng để gỡ lỗi" và đặt đó là dòng cuối cùng, trong proc được lưu trữ đang chạy và chạy dòng này:
call createARandomInString(4,18000000);
... để tạo 4 số ngẫu nhiên lên đến 18 triệu, kết quả có thể trông giống như
+-------------------------------------+
| myOutput |
+-------------------------------------+
| (2857561,5076608,16810360,14821977) |
+-------------------------------------+
Phụ lục E
Kiểm tra thực tế. Đây là những kỹ thuật hơi nâng cao và tôi không thể dạy kèm cho bất kỳ ai về chúng. Nhưng dù sao tôi cũng muốn chia sẻ chúng. Nhưng tôi không thể dạy nó. Hết và hết.