Ngăn chặn sao chép vào bảng tạm thời (sql)


7

Tôi có hai bảng - commentsvotes:

comments(id, text, user_id, page_id)  
votes(id, value)

Có 2.000.000 hàng trong votesbảng.

Tôi đã tạo truy vấn sau:

SELECT SUM(votes.value),
       comments.text,
       comments.comment_id 
FROM comments, votes 
WHERE comments.comment_id = votes.comment_id AND comments.page_id = $page_id 
GROUP BY comment_id;

Truy vấn chạy trong khoảng 12 giây, điều này có bình thường không?

SHOW PROCESSLISTnói rằng nó sao chép vào một bảng tạm thời. Điều này có vẻ chậm, có cần thiết phải sử dụng bảng tạm thời?


cơ sở dữ liệu và phiên bản nào (tôi giả sử MySQL)? Cũng có thể thuộc về trao đổi ngăn xếp DBA
Derek Downey

@Kev ahh, định dạng tốt hơn nhiều. Cảm ơn..tất cả đại diện của tôi để có thể làm điều đó :(
Derek Downey

Câu trả lời:


12

Trong thế giới của RDBMS, các bảng tạm thời là một thực tế của cuộc sống. Nó chỉ xé cái đầu xấu xí của nó trong THAM GIA .

Ngay cả trường hợp xấu nhất của THAM GIA là THAM GIA thoái hóa, truy vấn của một bảng.

Vì các bảng tạm thời luôn đi vào các truy vấn của chúng tôi (vào cuộc sống của chúng tôi), điều tốt nhất bạn có thể làm là bỏ đói các bảng tạm thời. Làm cho chúng nhỏ gọn nhất có thể. Ý tôi là sao ???

Đây là truy vấn của bạn:

SELECT SUM(votes.value),
       comments.text,
       comments.comment_id 
FROM comments, votes 
WHERE comments.comment_id = votes.comment_id AND comments.page_id = $page_id 
GROUP BY comment_id;

Bạn truy vấn sẽ thực sự tạo ra một bảng kết quả từ sự tham gia của các bình luận và phiếu bầu có số lượng hàng là 2.000.000 bình luận. Vì bảng tạm thời không có chỉ mục, nên luôn có các cartesian tham gia với các bảng tạm thời. Mệnh đề WHERE được áp dụng trên đường đi, sau đó là tổng hợp GROUP BY. Đừng quên, bảng tạm thời cũng sẽ chứa cột văn bản. Đó là rất nhiều dữ liệu văn bản để kéo xung quanh trong giai đoạn THAM GIA.

Hãy cấu trúc lại truy vấn của bạn

Bạn có thể tắt mệnh đề WHERE tại pass, có thể nói như vậy. Đây là cách thực hiện:

SELECT comment_id FROM comments WHERE page_id = $page_id;

Truy vấn này chỉ có các khóa cần thiết từ bảng ý kiến.

Tiếp theo, thu thập bình luận từ phiếu bầu

SELECT comment_id,SUM(value) sumofvalues FROM votes;

Đây thực sự là phần tồi tệ nhất. Với 2 triệu hàng và 4 byte cho mỗi comment_id và 4 byte cho tổng, đó là một bảng 16 MB trong trường hợp xấu nhất tuyệt đối.

Tiếp theo, kết hợp các phím bình luận với các khóa trùng khớp trong phiếu bầu.

SELECT BB.* FROM
(SELECT comment_id FROM comments WHERE page_id = $page_id) AA
INNER JOIN
(SELECT comment_id,SUM(value) sumofvalues FROM votes GROUP BY comment_id) BB
USING (comment_id);

Bây giờ các khóa từ các bình luận và tổng các giá trị từ các phiếu được lấy ra, phần cuối cùng là kết nối các id bình luận trở lại bảng bình luận ban đầu và lấy các trường văn bản.

SELECT
    B.sumofvalues,A.text,A.comment_id
FROM
    comments A INNER JOIN
    (
        SELECT BB.*
        FROM
            (SELECT comment_id FROM comments WHERE page_id = $page_id) AA
        INNER JOIN
            (SELECT comment_id,SUM(value) sumofvalues
            FROM votes GROUP BY comment_id) BB
        USING (comment_id)
    ) B
USING (comment_id);

Trước khi truy vấn được cấu trúc lại này có thể hoạt động nhanh nhất có thể, bạn sẽ cần lập chỉ mục thích hợp.

Dưới đây là các chỉ mục bạn cần:

ALTER TABLE comments ADD INDEX pageid_commentid_ndx (page_id,comment_id);
ALTER TABLE votes ADD INDEX commentid_value_ndx (comment_id,value);

Bạn muốn chỉ mục đầu tiên vì nó sẽ nhóm các hàng theo page_id. Bạn muốn chỉ mục thứ hai vì Nó sẽ nhóm các hàng theo comment_id. Trong thực tế, cả hai chỉ số này được gọi là chỉ số bao trùm . Tại sao điều đó quan trọng ??? Điều này rất quan trọng vì các truy vấn con sẽ chỉ lấy dữ liệu cần thiết từ chỉ mục, không bao giờ chạm vào bảng chính. Bảng ý kiến ​​chỉ được truy cập một lần khi tất cả các khóa cần thiết được biên dịch cùng nhau trong các truy vấn con.

Hãy thử một lần !!!

Nếu bất kỳ cú pháp nào không hoạt động, xin vui lòng bình luận về câu hỏi và cho tôi biết !!!


6

Giả sử đây là MySQL, bạn có thể sử dụng EXPLAINcú pháp để giúp tìm ra cách truy vấn đang được chạy:

EXPLAIN SELECT SUM(votes.value),comments.text,comments.comment_id FROM comments,votes    
WHERE comments.comment_id = votes.comment_id AND comments.page_id = $page_id 
GROUP BY comment_id;

Đầu tiên đoán là bạn sẽ cần các chỉ mục trên các cột mà bạn đang tham gia trên bảng phiếu bầu.


Điều này xứng đáng được +1 vì ba (3) lý do: 1) Câu trả lời phù hợp với những người tự học, 2) Phản ứng của câu trả lời của bạn, 3) Bạn đặt Hướng cho mọi người thực hiện lập chỉ mục khi EXPLAIN tiết lộ truy vấn hành vi.
RolandoMySQLDBA
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.