Tôi đang tối ưu hóa nhiều truy vấn hiện có trong dự án của mình. Giải pháp của Quassnoi đã giúp tôi tăng tốc các truy vấn rất nhiều! Tuy nhiên, tôi thấy khó có thể kết hợp giải pháp đã nói trong tất cả các truy vấn, đặc biệt là đối với các truy vấn phức tạp liên quan đến nhiều truy vấn con trên nhiều bảng lớn.
Vì vậy, tôi đang sử dụng giải pháp ít được tối ưu hóa hơn. Về cơ bản nó hoạt động theo cách tương tự như giải pháp của Quassnoi.
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor/[accomodation_table_row_count]
LIMIT $size
$size * $factor/[accomodation_table_row_count]
hoạt động ra khả năng chọn một hàng ngẫu nhiên. Rand() sẽ tạo ra một số ngẫu nhiên. Hàng sẽ được chọn nếu rand() nhỏ hơn hoặc bằng với xác suất. Điều này có hiệu quả thực hiện một lựa chọn ngẫu nhiên để giới hạn kích thước bảng. Vì có khả năng nó sẽ trả lại ít hơn số lượng giới hạn đã xác định, chúng tôi cần tăng xác suất để đảm bảo chúng tôi đang chọn đủ hàng. Do đó chúng tôi nhân kích thước $ với một yếu tố $ (tôi thường đặt $ factor = 2, hoạt động trong hầu hết các trường hợp). Cuối cùng, chúng tôi thực hiện limit $size
Sự cố hiện đang làm việc trên accomodation_table_row_count. Nếu chúng ta biết kích thước bảng, chúng tôi có thể mã hóa cứng kích thước bảng. Điều này sẽ chạy nhanh nhất, nhưng rõ ràng đây không phải là lý tưởng. Nếu bạn đang sử dụng Myisam, việc đếm bảng rất hiệu quả. Kể từ khi tôi đang sử dụng innodb, tôi chỉ làm một số đơn giản + lựa chọn. Trong trường hợp của bạn, nó sẽ trông như sau:
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor/(select (SELECT count(*) FROM `accomodation`) * (SELECT count(*) FROM `accomodation_category`))
LIMIT $size
Phần khó khăn là xác định đúng xác suất. Như bạn có thể thấy mã sau đây thực sự chỉ tính toán kích thước bảng tạm thời thô (Trong thực tế, quá thô!): (select (SELECT count(*) FROM accomodation) * (SELECT count(*) FROM accomodation_category))
Nhưng bạn có thể tinh chỉnh logic này để cung cấp cho một xấp xỉ kích thước bảng gần đúng hơn. Lưu ý rằng tốt hơn là chọn OVER hơn so với các hàng không chọn. tức là nếu xác suất được đặt quá thấp, bạn có nguy cơ không chọn đủ hàng.
Giải pháp này chạy chậm hơn giải pháp của Quassnoi vì chúng tôi cần phải tính toán lại kích thước bảng. Tuy nhiên, tôi thấy mã này dễ quản lý hơn nhiều. Đây là giao dịch giữa độ chính xác + hiệu suất so với độ phức tạp mã hóa. Có nói rằng, trên bảng lớn này vẫn còn nhanh hơn nhiều so với Order by Rand().
Lưu ý: Nếu logic truy vấn cho phép, hãy thực hiện lựa chọn ngẫu nhiên càng sớm càng tốt trước mọi hoạt động nối.
Có thể trùng lặp [MySQL chọn 10 hàng ngẫu nhiên từ hàng 600K nhanh] (http://stackoverflow.com/questions/4329396/mysql-select-10-random-rows-from-600k-rows-fast) –