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

Cách cải thiện hiệu suất truy vấn trong tìm kiếm quản trị Django trên các trường liên quan (MySQL)

Sau nhiều cuộc điều tra, tôi nhận thấy rằng vấn đề đến từ cách tạo truy vấn tìm kiếm cho trường tìm kiếm quản trị viên (trong ChangeList lớp). Trong tìm kiếm nhiều cụm từ (các từ được phân tách bằng dấu cách), mỗi cụm từ được thêm vào QuerySet bằng cách chuỗi một filter() mới . Khi có một hoặc nhiều trường liên quan trong search_fields , truy vấn SQL được tạo sẽ có rất nhiều JOIN lần lượt được xâu chuỗi với nhiều JOIN cho từng trường liên quan (xem câu hỏi liên quan cho một số ví dụ và thêm thông tin). Chuỗi JOIN này ở đó để mỗi cụm từ sẽ chỉ được tìm kiếm trong tập hợp con của bộ lọc dữ liệu theo cụm từ trước VÀ, điều quan trọng nhất là trường liên quan chỉ cần có một cụm từ (so với cần có TẤT CẢ cụm từ) để so khớp. Xem Mở rộng mối quan hệ nhiều giá trị trong tài liệu Django để biết thêm thông tin về chủ đề này. Tôi khá chắc rằng đó là hành vi hầu hết thời gian mong muốn đối với trường tìm kiếm quản trị viên.

Hạn chế của truy vấn này (có liên quan đến các trường liên quan) là sự thay đổi về hiệu suất (thời gian để thực hiện truy vấn) có thể thực sự lớn. Nó phụ thuộc vào rất nhiều yếu tố:số lượng cụm từ được tìm kiếm, cụm từ được tìm kiếm, loại tìm kiếm trường (VARCHAR, v.v.), số lượng trường tìm kiếm, dữ liệu trong bảng, kích thước của bảng, v.v. Với sự kết hợp phù hợp, thật dễ dàng để có một truy vấn sẽ mất gần như mãi mãi (truy vấn mất hơn 10 phút đối với tôi. Đối với tôi là một truy vấn mất vĩnh viễn trong ngữ cảnh của trường tìm kiếm này).

Lý do tại sao có thể mất nhiều thời gian như vậy là cơ sở dữ liệu cần phải tạo một bảng tạm thời cho mỗi thuật ngữ và quét nó gần như toàn bộ để tìm kiếm thuật ngữ tiếp theo. Vì vậy, điều này tăng lên thực sự nhanh chóng.

Một thay đổi có thể thực hiện để cải thiện hiệu suất là ANDed tất cả các thuật ngữ trong cùng một filter() . Bằng cách này, họ sẽ chỉ có một JOIN theo trường liên quan (hoặc 2 nếu là nhiều đến nhiều) thay vì nhiều trường khác. Truy vấn này sẽ nhanh hơn rất nhiều và với sự thay đổi hiệu suất thực sự nhỏ. Hạn chế là các trường liên quan sẽ phải có TẤT CẢ các thuật ngữ để khớp, do đó, bạn có thể nhận được ít kết quả phù hợp hơn trong nhiều trường hợp.

CẬP NHẬT

Theo yêu cầu của trinchet đây là những gì cần thiết để thực hiện thay đổi hành vi tìm kiếm (đối với Django 1.7). Bạn cần ghi đè get_search_results() của các lớp quản trị nơi bạn muốn tìm kiếm kiểu này. Bạn cần sao chép tất cả mã phương thức từ lớp cơ sở (ModelAdmin ) đến lớp học của riêng bạn. Sau đó, bạn cần thay đổi các dòng đó:

for bit in search_term.split():
    or_queries = [models.Q(**{orm_lookup: bit})
                  for orm_lookup in orm_lookups]
    queryset = queryset.filter(reduce(operator.or_, or_queries))

Vì điều đó:

and_queries = []
for bit in search_term.split():
    or_queries = [models.Q(**{orm_lookup: bit})
                  for orm_lookup in orm_lookups]
    and_queries.append(Q(reduce(operator.or_, or_queries)))
queryset = queryset.filter(reduce(operator.and_, and_queries))

Mã này không được kiểm tra. Mã ban đầu của tôi là cho Django 1.4 và tôi chỉ điều chỉnh nó cho 1.7 tại đây.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sử dụng MySql giữa mệnh đề với ngày tháng

  2. 2 bảng này yêu cầu quan hệ gì?

  3. Hibernate, MySQL và bảng có tên Lặp lại - hành vi lạ

  4. PHP PDO không đưa ra ngoại lệ khi chèn khóa trùng lặp

  5. Cài đặt MySQL trên máy Mac