Tôi đang tối ưu hóa rất 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 thật khó để 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 một giải pháp ít tối ưu hơn. Về cơ bản, nó hoạt động giống 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]
tính ra xác suất 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 xác suất. Điều này thực hiện một cách hiệu quả 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ả về í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 ta nhân $ size với $ factor (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 làmlimit $size
Sự cố hiện đang giải quyết số lượng 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 kích thước bảng. Điều này sẽ chạy nhanh nhất, nhưng rõ ràng điều nà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ả. Vì tôi đang sử dụng innodb nên tôi chỉ thực hiện một phép đếm + lựa chọn đơn giản. Trong trường hợp của bạn, nó sẽ giố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à tìm ra xác suất đúng. Như bạn có thể thấy đoạn mã sau thực tế chỉ tính toán kích thước bảng tạm thời thô (Trên 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 để đưa ra giá trị 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 QUÁ hơn là chọn dưới các hàng. 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 so với giải pháp của Quassnoi vì chúng ta cần tính toán lại kích thước bảng. Tuy nhiên, tôi thấy việc viết mã này dễ quản lý hơn rất nhiều. Đây là sự đánh đổi giữa độ chính xác + hiệu suất và độ phức tạp của mã hóa . Phải nói rằng, trên các bảng lớn, điều này vẫ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 bất kỳ hoạt động nối nào.