2012-03-28 42 views
5

Tôi đang tìm một cách hiệu quả để chọn ngẫu nhiên 100 hàng thỏa mãn các điều kiện nhất định từ một bảng MySQL với hàng triệu hàng.Làm thế nào để chọn ngẫu nhiên nhiều hàng thỏa mãn các điều kiện nhất định từ một bảng MySQL?

Hầu hết mọi thứ tôi đã tìm thấy đều đề nghị tránh sử dụng ORDER BY RAND() vì hiệu suất và khả năng mở rộng kém.

Tuy nhiên, this article đề xuất ORDER BY RAND() vẫn có thể được sử dụng làm "cách tốt đẹp và nhanh chóng" để tìm nạp dữ liệu randow.

Dựa trên bài viết này, dưới đây là một số mã ví dụ cho thấy những gì tôi đang cố gắng hoàn thành. Câu hỏi của tôi là:

  1. Đây có phải là cách hiệu quả để chọn ngẫu nhiên 100 (hoặc tới vài trăm) hàng từ một bảng có khả năng là hàng triệu hàng không?

  2. Khi nào hiệu suất sẽ trở thành sự cố?

 
    SELECT user.* 
    FROM (
      SELECT id 
      FROM user 
      WHERE is_active = 1 
      AND  deleted = 0 
      AND  expiretime > '.time().' 
      AND  id NOT IN (10, 13, 15) 
      AND  id NOT IN (20, 30, 50) 
      AND  id NOT IN (103, 140, 250) 
     ORDER BY RAND() 
      LIMIT 100 
      ) 
      AS  random_users 
    STRAIGHT JOIN user 
    ON  user.id = random_users.id 
+0

Có ý nghĩa khi chọn các giá trị ngẫu nhiên trên một trường có chỉ mục. – Kayser

+0

@Kayser, tôi lo ngại rằng chúng tôi vẫn phải quét TẤT CẢ các hàng cho điều kiện WHERE. Điều đó sẽ ảnh hưởng đến hiệu suất với một bảng lớn (có khả năng là hàng triệu hàng)? – user1298692

+0

Phương pháp với tùy chọn pk-subselect có khả năng chỉ giảm nhẹ thời gian thực hiện. Đó là bởi vì có hoặc không có kỹ thuật này, rand() được gọi cho tất cả các hàng phù hợp và số hàng cần sắp xếp giống nhau. Có lẽ điều này là thú vị nếu "người dùng" có nhiều cột hoặc kích thước cột lớn và mysql không đủ thông minh để chờ đợi sau khi LIMIT diễn ra để hiện thực hóa người dùng. * (Cần được kiểm tra). –

Trả lời

0

Tôi sợ không ai sẽ có thể trả lời câu hỏi của bạn với bất kỳ chính xác. Nếu bạn thực sự muốn biết bạn sẽ cần phải chạy một số điểm chuẩn so với hệ thống của bạn (không phải là một live lý tưởng nhưng là một bản sao chính xác). Đo điểm chuẩn giải pháp này dựa vào một giải pháp khác (ví dụ như lấy các hàng ngẫu nhiên bằng cách sử dụng PHP) và so sánh các con số với những gì bạn/khách hàng xem là "hiệu suất tốt". như bạn có thể và xem nơi hiệu suất bắt đầu thả ra.Để trung thực nếu nó làm việc cho bạn ngay bây giờ với một chút khoảng không, sau đó tôi muốn đi cho nó.Khi (nếu!) nó trở thành một nút cổ chai sau đó bạn có thể nhìn vào nó một lần nữa - hoặc chỉ cần bổ sung thêm sắt vào cơ sở dữ liệu của bạn ...

1

Rất mong bạn đọc đoạn mã này article.Phần cuối cùng sẽ bao gồm việc lựa chọn nhiều hàng ngẫu nhiên và bạn có thể nhận thấy câu lệnh SELECT các PROCEDURE sẽ được mô tả ở đó.Đó sẽ là nơi bạn thêm WHERE con cụ thể của bạn ditions.

Vấn đề với ORDER BY RAND() là hoạt động này có độ phức tạp của n*log2(n), trong khi phương pháp được mô tả trong bài viết mà tôi liên kết, có độ phức tạp gần như không đổi.

Cho phép giả định, rằng việc lựa chọn hàng ngẫu nhiên từ bảng, trong đó có 10 mục, sử dụng ORDER BY RAND() mất 1 time unit:

entries | time units 
------------------------- 
     10 |   1  /* if this takes 0.001s */ 
     100 |  20 
    1'000 |  300 
    10'000 |  4'000 
    100'000 | 50'000 
1'000'000 | 600'000  /* then this will need 10 minutes */ 

Và bạn viết rằng bạn đang đối phó với bảng trên quy mô của hàng triệu người.

0

preprocess càng nhiều càng tốt thử một cái gì đó tương tự (VB-giống như ví dụ)

Dim sRND = New StringBuilder : Dim iRandom As New Random() 
Dim iMaxID As Integer = **put you maxId here** 
Dim Cnt as Integer=0 
While Cnt < 100 
     Dim RndVal As Integer = iRandom.Next(1, iMaxID) 
     If Not ("10,13,15,20,30,50,103,140,250").Contains(RndVal) Then 
      Cnt += 1 
      sRND.Append("," & RndVal) 
     end if 
End While 
String.Format("SELECT * FROM (Select ID FROM(User) WHERE(is_active = 1) AND deleted = 0 AND expiretime > {0} AND id IN ({1}) .blahblablah.... LIMIT 100",time(), Mid(sRND.ToString, 2)) 

tôi đã không kiểm tra cú pháp, nhưng bạn sẽ nhận được trôi dạt của tôi, tôi hy vọng. Điều này sẽ làm cho MySql đọc hồ sơ phù hợp với 'IN' và dừng lại khi nó đạt đến 100 mà không cần phải xử lý trước tất cả các bản ghi đầu tiên.

Vui lòng cho tôi biết sự khác biệt thời gian trôi qua nếu bạn thử. (Tôi là qurious)

Các vấn đề liên quan