Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Làm cách nào để tránh quét toàn bộ bảng trên truy vấn mysql này?

Dựa trên EXPLAIN đầu ra trong câu hỏi của bạn, bạn đã có tất cả các chỉ mục mà truy vấn nên đang sử dụng, cụ thể là:

CREATE INDEX idx_zip_from_distance
  ON zipcode_distances (zipcode_from, distance, zipcode_to);
CREATE INDEX idx_zipcode ON venues (zipcode, id);
CREATE INDEX idx_venue_id ON events (venue_id);

(Tôi không chắc về tên chỉ mục của bạn liệu idx_zip_from_distance thực sự bao gồm zipcode_to cột. Nếu không, bạn nên thêm nó để làm cho nó trở thành chỉ mục bao gồm . Ngoài ra, tôi đã bao gồm venues.id trong idx_zipcode để hoàn thiện, nhưng, giả sử đó là khóa chính của bảng và bạn đang sử dụng InnoDB, thì nó sẽ tự động được đưa vào.)

Tuy nhiên, có vẻ như MySQL đang chọn một kế hoạch truy vấn khác, và có thể là không tối ưu, nơi nó quét qua tất cả các sự kiện, tìm địa điểm và mã zip của chúng và chỉ sau đó lọc kết quả theo khoảng cách. Điều này có thể là kế hoạch truy vấn tối ưu, nếu bản số của bảng sự kiện đủ thấp, nhưng từ thực tế là bạn đang hỏi câu hỏi này, tôi cho rằng không phải vậy.

Một lý do cho kế hoạch truy vấn tối ưu có thể thực tế là bạn có quá nhiều chỉ mục gây nhầm lẫn cho người lập kế hoạch. Ví dụ, bạn có thực sự không cần cả ba chỉ mục đó trên bảng mã zip, cho rằng dữ liệu mà nó lưu trữ có lẽ là đối xứng? Cá nhân tôi chỉ đề xuất chỉ mục mà tôi đã mô tả ở trên, cộng với một chỉ mục duy nhất (cũng có thể là khóa chính, nếu bạn không có chỉ mục nhân tạo) trên (zipcode_to, zipcode_from) (tốt nhất là theo thứ tự đó, để thỉnh thoảng có bất kỳ truy vấn nào trên zipcode_to=? có thể tận dụng nó).

Tuy nhiên, dựa trên một số thử nghiệm tôi đã thực hiện, tôi nghi ngờ vấn đề chính tại sao MySQL chọn sai kế hoạch truy vấn chỉ đơn giản là do các bản số tương đối của bảng của bạn. Có lẽ là zipcode_distances thực tế của bạn bảng là rất lớn và MySQL không đủ thông minh để nhận ra có bao nhiêu điều kiện trong WHERE thực sự thu hẹp nó lại.

Nếu vậy, cách khắc phục tốt nhất và đơn giản nhất có thể là chỉ cần buộc MySQL để sử dụng các chỉ mục bạn muốn :

select
    *
from
    zipcode_distances z 
    FORCE INDEX (idx_zip_from_distance)
inner join
    venues v    
    FORCE INDEX (idx_zipcode)
    on z.zipcode_to=v.zipcode
inner join
    events e
    FORCE INDEX (idx_venue_id)
    on v.id=e.venue_id
where
    z.zipcode_from='92108' and
    z.distance <= 5

Với truy vấn đó, bạn thực sự sẽ nhận được kế hoạch truy vấn mong muốn. (Bạn cần FORCE INDEX tại đây, vì chỉ với USE INDEX người lập kế hoạch truy vấn vẫn có thể quyết định sử dụng quét bảng thay vì chỉ mục được đề xuất, không đạt được mục đích. Tôi đã có điều này xảy ra khi tôi thử nghiệm điều này lần đầu tiên.)

Ps. Đây là bản trình diễn về SQLize, cả với không có FORCE INDEX , chứng minh vấn đề.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tại sao MySQL thêm nhận xét vào các bảng InnoDB?

  2. Tìm tháng tiếp theo cho ngày nhất định trong mysql

  3. Cách kết nối với cơ sở dữ liệu bằng Sequel Pro

  4. Sử dụng MySQL trong môi trường thương mại có hợp pháp không?

  5. Cái nào nhanh hơn:MySQL / PHP hay phân phát trực tiếp từ các tệp tĩnh?