Đây là một cách tiếp cận khác.
Truy vấn này sẽ gặp vấn đề về hiệu năng giống như các truy vấn khác ở đây trả về kết quả chính xác, vì kế hoạch thực hiện cho truy vấn này sẽ yêu cầu thao tác SORT trên hàng MỌI trong bảng thống kê. Vì không có biến vị ngữ (giới hạn) trên cột thời gian, nên mọi hàng trong bảng thống kê sẽ được xem xét. Đối với một bảng lớn stats
thực sự, điều này sẽ thổi ra tất cả không gian tạm thời có sẵn trước khi nó chết một cái chết khủng khiếp. (Thêm ghi chú về hiệu suất bên dưới.)
SELECT r.*
, IFNULL(s.avg_votes,0)
FROM servers r
LEFT
JOIN (SELECT t.server
, AVG(t.votes) AS avg_votes
FROM (SELECT CASE WHEN u.server = @last_server
THEN @i := @i + 1
ELSE @i := 1
END AS i
, @last_server := u.server AS `server`
, u.votes AS votes
FROM (SELECT @i := 0, @last_server := NULL) i
JOIN (SELECT v.server, v.votes
FROM stats v
ORDER BY v.server DESC, v.time DESC
) u
) t
WHERE t.i <= 24
GROUP BY t.server
) s
ON s.server = r.id
Truy vấn này đang sắp xếp bảng thống kê, theo máy chủ và theo thứ tự giảm dần trên cột thời gian. (Chế độ xem nội tuyến được đặt tên là u
.)
Với tập hợp kết quả được sắp xếp, chúng tôi gán một số hàng 1,2,3, v.v ... cho mỗi hàng cho mỗi máy chủ. (Chế độ xem nội dòng được đặt biệt hiệu là t
.)
Với tập hợp kết quả đó, chúng tôi lọc ra bất kỳ hàng nào có giá trị> 24 và chúng tôi tính trung bình của cột votes
cho 24 hàng "mới nhất" cho mỗi máy chủ. (Chế độ xem nội tuyến được đặt tên là s
.)
Bước cuối cùng, chúng tôi kết hợp với bảng máy chủ để trả về kết quả được yêu cầu.
LƯU Ý:
Các kế hoạch thực hiện cho truy vấn này sẽ tốn kém cho một số lượng lớn các hàng trong bảng stats
.
Để cải thiện hiệu suất, có một số phương pháp chúng tôi có thể thực hiện.
Đơn giản nhất có thể được bao gồm trong truy vấn vị từ EXCLUDES một số lượng đáng kể các hàng từ bảng stats
(ví dụ: các hàng có giá trị trên 2 ngày hoặc hơn 2 tuần). Điều đó sẽ làm giảm đáng kể số hàng cần được sắp xếp, để xác định 24 hàng mới nhất.
Ngoài ra, với chỉ mục trên stats(server,time)
, cũng có thể là MySQL có thể thực hiện "quét đảo ngược" tương đối hiệu quả trên chỉ mục, tránh hoạt động sắp xếp.
Chúng tôi cũng có thể xem xét triển khai chỉ mục trên bảng thống kê trên (server,"reverse_time")
. Vì MySQL chưa hỗ trợ các chỉ số giảm dần, việc triển khai thực sự sẽ là chỉ số thường xuyên (tăng dần) trên giá trị rtime
bắt nguồn (biểu thức "đảo ngược thời gian" tăng dần cho giá trị giảm dần của time
(ví dụ: -1*UNIX_TIMESTAMP(my_timestamp)
hoặc -1*TIMESTAMPDIFF('1970-01-01',my_datetime)
.
Một cách tiếp cận khác để cải thiện hiệu suất là giữ một bảng bóng chứa 24 hàng gần đây nhất cho mỗi máy chủ. Về cơ bản, bất cứ khi nào một hàng được chèn vào bảng stats
, chúng tôi kiểm tra xem time
trên các hàng mới có muộn hơn time
sớm nhất được lưu trữ cho máy chủ trong bóng tối hay không. bảng, nếu có, chúng tôi thay thế hàng sớm nhất trong bảng bóng với hàng mới, đảm bảo giữ không quá 24 hàng trong bảng bóng cho mỗi máy chủ.
Và, cách tiếp cận khác là viết thủ tục hoặc chức năng nhận kết quả. Cách tiếp cận ở đây sẽ là lặp qua mỗi máy chủ và chạy truy vấn riêng biệt với bảng thống kê để nhận số trung bình votes
cho 24 hàng mới nhất và thu thập tất cả các kết quả đó cùng nhau. (Đó là cách tiếp cận hùng mạnh thực sự được nhiều hơn một cách giải quyết để tránh một loại trên bộ tạm thời rất lớn, chỉ để cho phép resultset được trả lại, không nhất thiết làm cho sự trở lại của resultset blazingly nhanh.)
Dòng dưới cùng cho hiệu suất của kiểu truy vấn này trên bảng LARGE đang hạn chế số hàng được truy vấn xem xét và tránh thao tác sắp xếp trên một tập hợp lớn. Đó là cách chúng tôi nhận được một truy vấn như thế này để thực hiện.
PHỤ LỤC
Để có được một "ngược chỉ số quét" hoạt động (để lấy hàng từ stats
ra lệnh sử dụng một chỉ số KHÔNG một hoạt động filesort), tôi đã xác định giảm dần ở cả hai biểu thức trong Mệnh đề ORDER BY. Truy vấn ở trên trước đây có ORDER BY server ASC, time DESC
và MySQL luôn muốn thực hiện một tệp, thậm chí chỉ định gợi ý FORCE INDEX FOR ORDER BY (stats_ix1)
.
Nếu yêu cầu trả lại 'số phiếu trung bình' cho máy chủ chỉ nếu có ít nhất 24 hàng được liên kết trong bảng thống kê, thì chúng tôi có thể thực hiện truy vấn hiệu quả hơn, ngay cả khi lộn xộn. (Hầu hết sự lộn xộn trong hàm IF() lồng nhau là đối phó với các giá trị NULL, không được bao gồm trong giá trị trung bình, có thể ít lộn xộn hơn nếu chúng ta bảo đảm rằng votes
là NOT NULL, hoặc nếu chúng ta loại trừ bất kỳ hàng nơi votes
là NULL.)
SELECT r.*
, IFNULL(s.avg_votes,0)
FROM servers r
LEFT
JOIN (SELECT t.server
, t.tot/NULLIF(t.cnt,0) AS avg_votes
FROM (SELECT IF(v.server = @last_server, @num := @num + 1, @num := 1) AS num
, @cnt := IF(v.server = @last_server,IF(@num <= 24, @cnt := @cnt + IF(v.votes IS NULL,0,1),@cnt := 0),@cnt := IF(v.votes IS NULL,0,1)) AS cnt
, @tot := IF(v.server = @last_server,IF(@num <= 24, @tot := @tot + IFNULL(v.votes,0) ,@tot := 0),@tot := IFNULL(v.votes,0) ) AS tot
, @last_server := v.server AS SERVER
-- , v.time
-- , v.votes
-- , @tot/NULLIF(@cnt,0) AS avg_sofar
FROM (SELECT @last_server := NULL, @num:= 0, @cnt := 0, @tot := 0) u
JOIN stats v FORCE INDEX FOR ORDER BY (stats_ix1)
ORDER BY v.server DESC, v.time DESC
) t
WHERE t.num = 24
) s
ON s.server = r.id
với chỉ số bao phủ trên stats(server,time,votes)
, các giải thích cho thấy MySQL tránh một hoạt động filesort, vì vậy nó phải đã sử dụng một "ngược chỉ số quét" để trả lại hàng trong trật tự. Không có chỉ mục bao gồm, và chỉ mục trên '(máy chủ, thời gian) , MySQL used the index if I included an index hint, with the
FORCE INDEX FOR ORDER BY (stats_ix1) `gợi ý, MySQL tránh một filesort là tốt. (Nhưng kể từ khi bảng của tôi có ít hơn 100 hàng, tôi không nghĩ rằng MySQL chú trọng nhiều vào việc tránh một hoạt động tập hợp.)
Biểu thức thời gian, phiếu bầu và avg_sofar được nhận xét (trong chế độ xem nội dòng được đặt tên là t
); chúng không cần thiết, nhưng chúng là để gỡ lỗi.
Cách truy vấn đó đứng, nó cần ít nhất 24 hàng trong thống kê cho mỗi máy chủ, để trả về mức trung bình. (Điều đó có thể chấp nhận được.) Nhưng tôi đã nghĩ rằng nói chung, chúng ta có thể trả về tổng số đang chạy, tổng cộng cho đến nay (tot) và một số đếm (cnt).
(Nếu chúng ta thay thế WHERE t.num = 24
với WHERE t.num <= 24
, chúng ta có thể thấy tỷ lệ trung bình chạy trong hành động.)
Để trở về mức trung bình mà không có ít nhất 24 dòng trong số liệu thống kê, đó là thực sự là một vấn đề xác định hàng (cho mỗi máy chủ) với giá trị tối đa là num là < = 24.
Tôi tin rằng [this] (http://sqlfiddle.com/#!2/d908f/5) là cấu trúc bảng của bảng của bạn . Đúng? –