Cách tối ưu hóa các chỉ mục trên truy vấn MySQL với nhiều loại khác nhau


7

Tôi có một bảng INNODB levels:

+ -------------------- + -------------- + ------ + ----- + --------- + ------- +
| Lĩnh vực | Loại | Không | Chìa khóa | Mặc định | Thêm |
+ -------------------- + -------------- + ------ + ----- + --------- + ------- +
| id | int (9) | KHÔNG | PRI | NULL | |
| level_name | varar (20) | KHÔNG | | NULL | |
| user_id | int (10) | KHÔNG | | NULL | |
| tên người dùng | varar (45) | KHÔNG | | NULL | |
| đánh giá | số thập phân (5,4) | KHÔNG | | 0,0000 | |
| phiếu bầu | int (5) | KHÔNG | | 0 | |
| vở kịch | int (5) | KHÔNG | | 0 | |
| date_published | ngày | KHÔNG | MUL | NULL | |
| user_comment | varchar (255) | KHÔNG | | NULL | |
| playable_character | int (2) | KHÔNG | | 1 | |
| được bảo vệ | tí hon (1) | KHÔNG | MUL | 0 | |
+ -------------------- + -------------- + ------ + ----- + --------- + ------- +

Có ~ 4 triệu hàng. Do chức năng front-end, tôi cần truy vấn bảng này với nhiều bộ lọc và sắp xếp khác nhau. Họ đang ở trên playable_character, rating, plays, và date_published. Có date_publishedthể được lọc để hiển thị vào ngày cuối cùng, tuần, tháng hoặc bất cứ lúc nào (3 năm qua). Ngoài ra còn có phân trang. Vì vậy, tùy thuộc vào lựa chọn của người dùng, ví dụ, các truy vấn có thể trông giống như một trong những truy vấn sau:

SELECT * FROM levels
WHERE playable_character = 0 AND
    date_published BETWEEN date_sub(now(), INTERVAL 3 YEAR) AND now()
ORDER BY date_published DESC
LIMIT 0, 1000;

SELECT * FROM levels
WHERE playable_character = 4 AND
    date_published BETWEEN date_sub(now(), INTERVAL 1 WEEK) AND now()
ORDER BY rating DESC
LIMIT 4000, 1000;

SELECT * FROM levels
WHERE playable_character = 5 AND
    date_published BETWEEN date_sub(now(), INTERVAL 1 MONTH) AND now()
ORDER BY plays DESC
LIMIT 1000, 1000;

Tôi nên thêm nó ratingplaysluôn luôn được yêu cầu như DESC. Chỉ date_publishedcó thể là DESChay ASC.

Tôi đã bắt đầu với một chỉ mục idx_date_char(date_published, playable_character)hoạt động tốt trên truy vấn ví dụ đầu tiên ở đây. Dựa trên một số câu trả lời khác, tôi đã thay đổi thành hai chỉ mục khác (date_published, playable_character, Plays) và (date_published, playable_character, rating).

Truy vấn đầu tiên vẫn chạy rất nhanh, tuy nhiên có một số điều bất thường xảy ra trong EXPLAIN, khi player_character = x vượt quá một số hàng nhất định (~ 700.000): SỬ DỤNG WHERE xuất hiện trong EXPLAIN.

Vì vậy, câu hỏi đầu tiên là có bất kỳ cải tiến nào trong truy vấn hoặc chỉ mục có thể không, và thứ hai, những gì cài đặt MySQL sẽ được thay đổi để cho phép các tập kết quả lớn.

Bất kỳ đề xuất đánh giá rất cao. TIA.


Tôi chắc chắn muốn thấy đầu ra "giải thích" và "hiển thị chỉ mục từ các mức" khi có những điều bất thường xảy ra .. có vẻ như việc quét sâu (giá trị bắt đầu lớn hơn trong LIMIT) kích hoạt việc sử dụng bảng tạm thời và sử dụng tệp.
Raymond Nijland

Ngoài ra làm thế nào chậm chạy các truy vấn khác? Cần bao nhiêu thời gian để có kết quả?
Mindaugas Riauba

1
Đó không phải là một bản sao của câu hỏi này ?: stackoverflow.com/questions/19385610/...
ypercubeᵀᴹ

@ypercube chắc chắn trông giống như một bản sao tôi nghĩ rằng tôi đã có một Déjà vu nhưng tôi không thể tìm thấy chủ đề trên annymore stackoverflow
Raymond Nijland

@ Hal50000 Nếu phần giải thích của bạn hiển thị "bằng cách sử dụng filesort", tôi nghĩ rằng blog này.oracle.com / realneel / entry / Giả có thể là lưu ý vấn đề của bạn rằng bài viết đã cũ nên rất có thể các tập tin sẽ được gợi ý ngay bây giờ với gợi ý giải thích để có được ước tính_row_upper_bound ( ) xem sqlfiddle.com/#!2/4f56a/2, tôi nghĩ rằng các tập tin được 30 như là hàng ở đó .. tôi cũng nghĩ rằng tôi cần phải theo dõi ước tính_row_upper_bound () trong mã nguồn để giải thích rõ hơn đây là thoery.
Raymond Nijland

Câu trả lời:


2
WHERE playable_character = 0 AND
    date_published BETWEEN date_sub(now(), INTERVAL 3 YEAR) AND now()

Bắt đầu với mục "=", sau đó thực hiện phạm vi:

INDEX(playable_character, date_published);

"Chiếu", a la ORDER BY rating DESC LIMIT 4000, 1000;được thực hiện tốt nhất bằng cách nhớ nơi bạn "rời đi". Bằng cách đó, bạn không quét qua 4000 hồ sơ mà bạn không cần.


-1

tạo cả hai chỉ mục để có hiệu suất tốt hơn nếu không có nhiều truy vấn chèn hoặc cập nhật:

ADD INDEX (playable_character, date_published, rating desc)

ADD INDEX (playable_character, date_published, plays desc)

mặt khác, nếu chèn và cập nhật truy vấn được sử dụng nhiều hơn trên bảng này hơn là tạo chỉ mục:

ADD INDEX (playable_character, date_published)

hoặc không tạo bất kỳ chỉ mục


-2

Mọi người ở đây đều thiếu một điểm - SQL trong câu hỏi đang truy xuất 1000 hàng. Và người ta không thể truy xuất 1000 hàng nhanh trừ khi hầu hết dữ liệu được lưu trữ. Nếu dữ liệu không được lưu trong bộ nhớ cache, người ta phải thực hiện 1000 lần đọc ngẫu nhiên để lấy dữ liệu.

Lưu trữ dựa trên đĩa tốt với đĩa nhanh sẽ cung cấp cho bạn tới ~ 200 lần đọc mỗi giây. Các đĩa phổ biến ngay cả trong RAID Tôi nghi ngờ rằng quản lý thậm chí 100. Điều đó có nghĩa là hơn 10 giây để có kết quả ngay cả với các chỉ mục tốt nhất.

Vì vậy, về lâu dài mô hình dữ liệu và truy vấn như vậy sẽ không hoạt động. Bây giờ các truy vấn chạy nhanh khi bạn nhấn dữ liệu được lưu trữ.


Ngay cả với chỉ số bao gồm?
ypercubeᵀᴹ

Đó là một trong những ý tưởng có thể làm thế nào để sắp xếp lại dữ liệu.
Mindaugas Riauba

Các chỉ mục bao phủ cũng cho kết quả tốt nhất khi chúng được lưu trong bộ đệm. Nếu không, bạn phải chờ đợi vào I / O đĩa.
Bill Karwin

Và với giá trị của nó, các hệ thống dựa trên SSD với hàng ngàn IOPS đang trở thành xu hướng chủ đạo cho các máy chủ RDBMS.
Bill Karwin

1
Có nhiều hương vị của việc lập chỉ mục tốt / xấu - từ chỉ mục bao trùm đến quét bảng. Ở giữa là chỉ số không che phủ tối ưu, chỉ mục phụ tối ưu, quét phạm vi, tham gia không cần thiết, v.v ... Tìm nạp 1000 hàng có thể mất 0 I / O (chỉ mục tốt và bộ nhớ đệm tốt), tất cả đều đạt đến hơn 1000 lần truy cập đĩa ( bảng lớn, không có chỉ số hữu ích).
Rick James
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.