2012-06-20 15 views
9

Tôi đang chạy một truy vấn mà trông như thế nàySử dụng một chỉ mục trong MySQL JOIN với OR trạng

SELECT parent.field, child.field 
FROM parent 
JOIN child ON (child.id = parent.id 
    OR child.id = parent.otherid) 

Đây là tuy nhiên rất chậm (khoảng 100k hồ sơ, và tham gia vào các bảng khác trong phiên bản thực tế), nhưng mặc dù đã thử lập chỉ mục trên

parent.id (PRIMARY), 
parent.otherid, 
child.id (PRIMARY), 
and a composite index of parent.id and parent.otherid 

Tôi không thể sử dụng bất kỳ chỉ mục nào trong số các chỉ mục này khi tham gia.

Tôi đọc rằng MySQL chỉ có thể sử dụng một chỉ mục cho mỗi lần tham gia, nhưng không thể tìm thấy bất cứ nơi nào cho dù nó có thể sử dụng chỉ mục tổng hợp khi JOIN có chứa điều kiện OR.

Có ai ở đây biết liệu có thể làm cho truy vấn này tham chiếu đến chỉ mục không? Nếu có, làm thế nào?


GIẢI PHÁP CỦA TÔI

(SO sẽ không cho phép tôi trả lời câu hỏi của riêng tôi dưới đây atm)

Một loạt các tinh chỉnh và đã đưa ra một giải pháp khá phong nha mà vẫn giữ được khả năng JOIN và tổng hợp các bảng khác.

SELECT parent.field, child.field 
FROM parent 
JOIN (
    SELECT parent.id as parentid, 
    # Prevents the need to union 
    IF(NOT ISNULL(parent.otherid) AND parent.otherid <> parent.id, 
     parent.otherid, 
     parent.id) as getdataforid 
    FROM parent 
    WHERE (condition) 
) as foundrecords 
    ON foundrecords.parentid = parent.id 
JOIN child ON child.id = parent.getdataforid 

Đối với tốc độ đòi hỏi một điều kiện bên trong subquery để giảm số lượng các hồ sơ đặt trong một bảng tạm thời, nhưng tôi có tấn phụ gia nhập vào truy vấn bên ngoài, một số tham gia cho đứa trẻ và một số để phụ huynh (với một số tập hợp) vì vậy điều này làm việc tốt nhất cho tôi.

Trong nhiều trường hợp, công đoàn sẽ nhanh hơn và hiệu quả hơn, nhưng vì tôi lọc theo cấp độ gốc, nhưng muốn có dữ liệu bổ sung từ trẻ em (tự tham khảo cha mẹ), công đoàn đã tạo thêm hàng cho tôi hợp nhất. Có thể kết quả tương tự có thể được tìm thấy chỉ bằng cách tham gia cha mẹ với chính nó và đánh dấu một điều kiện trong truy vấn bên ngoài, nhưng điều này hoạt động khá độc đáo đối với tôi.

Nhờ Jirka cho UNION ALL gợi ý, đó là những gì thúc đẩy tôi đến đây :)

+0

Cậu chạy 'giải thích chọn ... 'trên truy vấn? –

+1

yep, giải thích là những gì cho tôi biết nó không sử dụng bất kỳ chỉ mục nào cho việc tham gia này. –

Trả lời

7

truy vấn của bạn làm cho nó về mặt lý thuyết có thể là một đứa trẻ duy nhất có hai bố mẹ khác nhau, trong đó sẽ làm cho nó cho các thuật ngữ khá chuẩn. Tuy nhiên, hãy giả định rằng các mẫu dữ liệu của bạn làm cho điều đó là không thể.

Sau đó, điều sau đây cung cấp cho bạn kết quả tương tự bằng cách sử dụng các chỉ mục riêng biệt, một chỉ mục cho mỗi cột.

SELECT parent.field, child.field 
FROM parent 
JOIN child ON child.id = parent.id 

UNION ALL 

SELECT parent.field, child.field 
FROM parent 
JOIN child ON child.id = parent.otherid 
+0

+1. excatly những gì tôi sẽ đề nghị cố gắng, phá vỡ này thành hai truy vấn riêng biệt, và kết hợp các kết quả, mặc dù truy vấn này COULD trả lại hàng hơn so với truy vấn ban đầu. (Hãy xem xét một hàng trong cha mẹ, nơi id = otherid). Để đảm bảo cùng một kết quả, hãy thêm vị từ 'AND parent.otherid <> parent.id' trên truy vấn thứ hai đó. (NULLs không phải là một vấn đề trong thử nghiệm đó, vì parent.id là NOT NULL bởi vì nó là PRIMARY KEY.) – spencer7593

+1

Đây là một giải pháp tuyệt vời trong trường hợp đơn giản (cảm ơn), nhưng nó ngăn chặn tập hợp dữ liệu ở trẻ (sử dụng GROUP_CONCAT (DISTINCT child.field)). Chơi với ý tưởng mặc dù để xem nếu tôi có thể áp dụng nó để tăng tốc độ truy vấn tương tự nhưng không có tập hợp. Cảm ơn: D –

+2

@BobDavies - Bạn có thể. Nhúng dưới dạng truy vấn phụ. –

0
EXPLAIN 
SELECT parent.fld, child.fld 
    FROM parent JOIN child ON child.id = parent.id 
UNION ALL 
SELECT parent.fld, child.fld 
    FROM parent JOIN child ON child.id = parent.otherid 
    AND parent.otherid <> parent.id 

với các bảng sử dụng động cơ MyISAM:

id select_type TABLE  TYPE possible_keys KEY  key_len ref     ROWS Extra 
1 PRIMARY  parent  ALL  PRIMARY            9999 
1 PRIMARY  child  eq_ref PRIMARY  PRIMARY 4  test.parent.id  1 
2 UNION   parent  ALL  parent_ix1           9999 USING WHERE 
2 UNION   child  eq_ref PRIMARY  PRIMARY 4  test.parent.otherid 1 
    UNION RESULT <union1,2> ALL 

với các bảng sử dụng InnoDB động cơ:

id select_type table  type possible_keys key   key_len ref   rows Extra 
1 PRIMARY  child  ALL  PRIMARY           9903 
1 PRIMARY  parent  eq_ref PRIMARY  PRIMARY  4  test.child.id 1 
2 UNION   child  ALL  PRIMARY           9903 
2 UNION   parent  ref  parent_ix1  parent_ix1 5  test.child.id 1  Using where 
    UNION RESULT <union1,2> ALL 
Các vấn đề liên quan