2009-02-04 54 views
73

Tôi vừa có một truy vấn khá phức tạp mà tôi đang làm việc và đã mất 8 giây để chạy. GIẢI THÍCH đã cho thấy một thứ tự bảng lạ và các chỉ mục của tôi không được sử dụng ngay cả với gợi ý FORCE INDEX. Tôi đã xem qua từ khóa tham gia STRAIGHT_JOIN và bắt đầu thay thế một số từ khóa INNER JOIN của tôi bằng từ khóa đó. Tôi nhận thấy sự cải thiện đáng kể về tốc độ. Cuối cùng, tôi chỉ thay thế tất cả từ khóa INNER JOIN của mình bằng STRAIGHT_JOIN cho truy vấn này và bây giờ nó chạy trong 0,01 giây.Khi nào sử dụng STRAIGHT_JOIN với MySQL

Câu hỏi của tôi là khi nào bạn sử dụng STRAIGHT_JOIN và khi nào bạn sử dụng INNER JOIN? Có lý do nào để không sử dụng STRAIGHT_JOIN nếu bạn đang viết các truy vấn tốt không?

Trả lời

69

Tôi sẽ không khuyên bạn sử dụng STRAIGHT_JOIN mà không có lý do chính đáng. Kinh nghiệm của riêng tôi là trình tối ưu hóa truy vấn MySQL chọn một kế hoạch truy vấn nghèo thường xuyên hơn tôi muốn, nhưng không thường xuyên là bạn nên bỏ qua nó nói chung, đó là những gì bạn sẽ làm nếu bạn luôn sử dụng STRAIGHT_JOIN.

Đề xuất của tôi là để lại tất cả các truy vấn như JOIN thường xuyên. Nếu bạn phát hiện ra rằng một truy vấn đang sử dụng kế hoạch truy vấn phụ tối ưu, tôi sẽ đề nghị trước tiên cố gắng viết lại hoặc cấu trúc lại truy vấn một chút để xem liệu trình tối ưu hóa có chọn một kế hoạch truy vấn tốt hơn không. Ngoài ra, đối với innodb ít nhất, hãy chắc chắn rằng nó không chỉ là số liệu thống kê chỉ mục của bạn là out-of-date (ANALYZE TABLE). Điều đó có thể khiến trình tối ưu hóa chọn một kế hoạch truy vấn kém. Các gợi ý tối ưu hóa nói chung phải là phương sách cuối cùng của bạn.

Lý do khác không sử dụng gợi ý truy vấn là phân phối dữ liệu của bạn có thể thay đổi theo thời gian, hoặc khả năng chọn lọc chỉ mục của bạn có thể thay đổi, v.v. khi bảng của bạn tăng lên. Các gợi ý truy vấn của bạn giờ đây tối ưu, có thể trở thành tiểu tối ưu theo thời gian. Nhưng trình tối ưu hóa sẽ không thể điều chỉnh kế hoạch truy vấn vì các gợi ý đã lỗi thời của bạn. Bạn vẫn linh hoạt hơn nếu bạn cho phép trình tối ưu hóa đưa ra quyết định.

+1

Cảm ơn, lời giải thích tuyệt vời. – Greg

+27

Câu trả lời này không thực sự giải thích ** khi nào nên sử dụng ** 'straight_join'. – Pacerier

16

MySQL không nhất thiết phải lựa chọn thứ tự tham gia trong các truy vấn phức tạp. Bằng cách chỉ định một truy vấn phức tạp dưới dạng một straight_join truy vấn thực hiện các phép nối theo thứ tự chúng được chỉ định. Bằng cách đặt bảng là mẫu số chung ít nhất đầu tiên và chỉ định straight_join bạn có thể cải thiện hiệu suất truy vấn.

19

Từ MySQL JOIN reference:.

"STRAIGHT_JOIN cũng tương tự như JOIN, ngoại trừ các bảng bên trái luôn luôn đọc trước khi bảng bên phải này có thể được sử dụng cho những người (vài) Các trường hợp mà người tham gia tối ưu hóa đặt các bảng trong thứ tự sai. "

+10

Cảm ơn, nhưng tôi đã đọc hướng dẫn sử dụng MySQL trên đó. Hy vọng cho một số giải thích thêm. – Greg

10

STRAIGHT_JOIN, sử dụng mệnh đề này, bạn có thể kiểm soát thứ tự JOIN: bảng nào được quét trong vòng ngoài và vòng nào nằm trong vòng lặp bên trong.

+0

Vòng lặp ngoài và vòng lặp bên trong là gì? –

7

Đây là một tình huống mới xuất hiện gần đây tại nơi làm việc.

Xem xét ba bảng, A, B, C.

A có 3.000 hàng; B có 300.000.000 hàng; và C có 2.000 hàng.

Khóa ngoài được xác định: B (a_id), B (c_id).

Giả sử bạn có một truy vấn mà trông như thế này:

select a.id, c.id 
from a 
join b on b.a_id = a.id 
join c on c.id = b.c_id 

Theo kinh nghiệm của tôi, MySQL có thể chọn để đi C -> B -> A trong trường hợp này. C nhỏ hơn A và B là rất lớn, và tất cả chúng đều là equijoins.

Vấn đề là MySQL không nhất thiết phải tính đến kích thước giao điểm giữa (C.id và B.c_id) so với (A.id và B.a_id). Nếu sự kết hợp giữa B và C trả lại nhiều hàng như B, thì đó là một lựa chọn rất nghèo; nếu bắt đầu với A sẽ lọc B thành nhiều hàng như A, thì nó sẽ là một lựa chọn tốt hơn nhiều.

Nói chung, bạn muốn thực hiện các phép nối của mình theo thứ tự giảm thiểu số hàng trong tập hợp kết quả. Vì vậy, bắt đầu với một bảng nhỏ và tham gia như vậy mà kết quả tham gia cũng sẽ nhỏ, là lý tưởng. Mọi thứ có hình quả lê nếu bắt đầu bằng một chiếc bàn nhỏ và nối nó với một chiếc bàn lớn hơn, kết thúc bằng một chiếc bàn lớn.

Đó là số liệu thống kê phụ thuộc. Nếu thay đổi phân phối dữ liệu, phép tính có thể thay đổi. Nó cũng phụ thuộc vào các chi tiết thực hiện của cơ chế kết nối.

+0

Bạn sẽ sử dụng tham gia thẳng như thế nào để khắc phục sự cố? – Hannele

+0

@Hannele 'straight_join' đánh giá bảng bên trái trước bên phải. Vì vậy, nếu bạn muốn đi từ 'A -> B -> C' trong ví dụ của tôi, từ khóa' join' đầu tiên có thể được thay thế bằng 'straight_join'. –

+0

Ah gọn gàng. Sẽ hữu ích khi đưa vào ví dụ đó trong câu trả lời của bạn :) – Hannele

-4
--use 120s, 18 million data 
    explain SELECT DISTINCT d.taid 
    FROM tvassist_recommend_list_everyday_diverse d, tvassist_taid_all t 
    WHERE d.taid = t.taid 
     AND t.client_version >= '21004007' 
     AND t.utdid IS NOT NULL 
     AND d.recommend_day = '20170403' 
    LIMIT 0, 10000 

--use 3.6s repalce by straight join 
explain SELECT DISTINCT d.taid 
    FROM tvassist_recommend_list_everyday_diverse d 
    STRAIGHT_JOIN 
     tvassist_taid_all t on d.taid = t.taid 
    WHERE 
    t.client_version >= '21004007' 
     AND d.recommend_day = '20170403' 

     AND t.utdid IS NOT NULL 
    LIMIT 0, 10000 
+0

Điều này không cung cấp cho bạn thông tin gần như đủ để tìm ra khi kết nối thẳng là thích hợp. – Hannele

2

tôi sẽ cho bạn biết lý do tại sao tôi phải sử dụng STRAIGHT_JOIN:

  • Tôi đã có một hiệu suất vấn đề với một truy vấn.
  • Đơn giản hóa truy vấn, truy vấn suddently hiệu quả hơn
  • Cố gắng tìm ra phần cụ thể nào đang mang lại sự cố, tôi không thể. (2 trái tham gia cùng là chậm, và mỗi người là một cách độc lập nhanh)
  • sau đó tôi thực hiện các giải thích với cả hai truy vấn chậm và nhanh chóng (addind một trong những trái tham gia)
  • Đáng ngạc nhiên, MySQL đã thay đổi hoàn toàn JOIN lệnh giữa 2 truy vấn.

Vì vậy, tôi đã buộc một trong các kết nối phải thẳng tham gia FORCE lần kết nối trước được đọc trước tiên. Điều này ngăn cản MySQL thay đổi thứ tự thực hiện và làm việc như một sự quyến rũ!

Các vấn đề liên quan