2012-12-08 40 views
8

Tôi đã tạo 2 truy vấn mà tôi có thể sử dụng để thực hiện cùng một chức năng. Cả hai đều chứa các thuộc tính mà tôi muốn hợp nhất thành một truy vấn nhưng tôi không thể.Tối ưu hóa chỉ mục MySQL với Truy vấn con và So khớp trái

QUERY 1 - Cung cấp cho tôi chính xác kết quả tôi muốn. Chậm (~ 0.700 giây)

QUERY 2 - Cung cấp cho tôi nhiều hàng mà tôi bỏ qua và bỏ qua. Nhanh (~ 0,00 giây)

Mục tiêu của tôi là sửa đổi QUERY 2 để thả tất cả các hàng giá rỗng trừ 1 cho mỗi mục. Tôi dường như không thể làm điều này với việc tham gia vào buổi biểu diễn. Điều này là do tôi thiếu kinh nghiệm và hiểu biết về việc sử dụng chỉ mục trong MySQL.

QUERY 1

Sử dụng một subquery thiết kế kém mà không cho phép việc sử dụng các chỉ mục trên tbl_sale (e) trong đó có 10k hàng.

SELECT b.id, b.sv, b.description, der.store_id, f.name, der.price 
FROM tbl_watch AS a 
    LEFT JOIN tbl_item AS b ON a.item_id = b.id 
LEFT JOIN (
    SELECT c.store_id, d.flyer_id, e.item_id, e.price 
    FROM tbl_storewatch AS c, tbl_storeflyer AS d 
    FORCE INDEX (storebeg_ndx) , tbl_sale AS e 
    WHERE c.user_id = '$user_id' 
    AND (
     d.store_id = c.store_id 
     AND d.date_beg = '20121206' 
     ) 
    AND e.flyer_id = d.flyer_id 
     ) AS der ON a.item_id = der.item_id 
LEFT JOIN tbl_store as f ON der.store_id = f.id 
WHERE a.user_id = '$user_id' 
ORDER BY b.description ASC 

Dưới đây là giải thích cho QUERY 1

id select_type table  type possible_keys key    key_len  ref  rows Extra 
1 PRIMARY  a   ref  user_item_ndx user_item_ndx 4   const 30 Using index; Using temporary; Using filesort 
1 PRIMARY  b   eq_ref PRIMARY   PRIMARY   4   a.item_id 1 
1 PRIMARY  <derived2> ALL  NULL   NULL   NULL  NULL 300  
1 PRIMARY  f   eq_ref PRIMARY   PRIMARY   4   der.store_id 1 
2 DERIVED  c   ref  user_ndx  user_ndx  4     6 
2 DERIVED  e   ALL  NULL   NULL NULL NULL    9473 Using join buffer 
2 DERIVED  d   eq_ref storebeg_ndx storebeg_ndx 8   c.store_id 1 Using where 

QUERY 2

Sử dụng tất cả trái tham gia mà rất hiệu quả (với ngoại lệ của ORDER BY). Các chỉ mục được sử dụng trên mỗi lần tham gia. Truy vấn này trả về tất cả các kết quả phù hợp có thể cho mỗi mục trong tbl_watch. Dưới đây là các truy vấn:

SELECT b.id, b.sv, b.description, c.store_id, f.name, e.price 
FROM tbl_watch AS a 
LEFT JOIN tbl_item AS b ON a.item_id = b.id 
LEFT JOIN tbl_storewatch AS c ON c.user_id = '$user_id' 
LEFT JOIN tbl_storeflyer AS d ON d.store_id = c.store_id 
    AND d.date_beg = '$s_date' 
LEFT JOIN tbl_sale AS e ON e.item_id = a.item_id 
    AND e.flyer_id = d.flyer_id 
LEFT JOIN tbl_store as f ON d.store_id = f.id 
WHERE a.user_id = '$user_id' 
ORDER BY b.description ASC 

Sau đây là giải thích cho truy vấn:

id select_type  table type possible_keys   key    key_len  ref      rows Extra 
1 SIMPLE   a  ref  user_item_ndx   user_item_ndx 4   const     6  Using index; Using temporary; Using filesort 
1 SIMPLE   b  eq_ref PRIMARY     PRIMARY   4   a.item_id    1 
1 SIMPLE   c  ref  user_ndx    user_ndx  4   const     2 
1 SIMPLE   d  eq_ref storebeg_ndx,storendx storebeg_ndx 8   c.store_id,const  1 
1 SIMPLE   e  eq_ref itemflyer_ndx   itemflyer_ndx 8   a.item_id,d.flyer_id 1 
1 SIMPLE   f  eq_ref PRIMARY     PRIMARY   4   d.store_id    1 

Làm thế nào tôi có thể sửa đổi QUERY 2 (hiệu quả hơn) để cho tôi chỉ là hàng tôi cần như trong QUERY 1 tới làm việc với?

Cảm ơn Mike

+0

Tôi không thực sự chắc chắn về khả năng truy vấn đầu tiên cung cấp cho bạn những gì bạn muốn. Phép nối trái không phải là một phép nối ngoài bên trái (mặc dù có lẽ nó là trong MySQL, nó không tuân thủ SQL), và các giá trị rỗng không phải là các giá trị duy nhất. Tôi không có MySQL tiện dụng, nhưng thả nó vào PostgreSQL không đưa ra kết quả mà bạn mô tả. Câu trả lời của tôi dưới đây ... – PlexQ

Trả lời

0

subselect của bạn trong QUERY 1 đang sử dụng tiềm ẩn bên trong tham gia, trong khi truy vấn 2 được sử dụng tất cả trái tham gia rõ ràng tham gia. Vì vậy, không có điều khoản đó để loại trừ dữ liệu trong truy vấn 2. Tôi muốn đưa ra các LEFT trong một vài dòng (như đánh dấu) và xem cách này cải thiện điều:

SELECT b.id, b.sv, b.description, c.store_id, f.name, e.price 
FROM tbl_watch AS a 
LEFT JOIN tbl_item AS b ON a.item_id = b.id 
LEFT JOIN tbl_storewatch AS c ON c.user_id = '$user_id' 
-- Left removed below 
JOIN tbl_storeflyer AS d ON d.store_id = c.store_id 
    AND d.date_beg = '$s_date' 
-- Left removed below 
JOIN tbl_sale AS e ON e.item_id = a.item_id 
    AND e.flyer_id = d.flyer_id 
LEFT JOIN tbl_store as f ON d.store_id = f.id 
WHERE a.user_id = '$user_id' 
ORDER BY b.description ASC` 

Bạn cũng có thể xem xét việc và các mệnh đề ra khỏi các kết nối và chuyển chúng đến WHERE:

SELECT b.id, b.sv, b.description, c.store_id, f.name, e.price 
FROM tbl_watch AS a 
LEFT JOIN tbl_item AS b ON a.item_id = b.id 
LEFT JOIN tbl_storewatch AS c ON c.user_id = '$user_id' 
JOIN tbl_storeflyer AS d ON d.store_id = c.store_id 
JOIN tbl_sale AS e ON e.item_id = a.item_id 
LEFT JOIN tbl_store as f ON d.store_id = f.id 
WHERE a.user_id = '$user_id' 
AND d.date_beg = '$s_date' 
AND e.flyer_id = d.flyer_id 
ORDER BY b.description ASC 

và cuối cùng, toán ngày khá chuyên sâu. Trong truy vấn 2, sử dụng các phép nối ngoài, bạn tránh rất nhiều, nhưng bạn có thể cần nó. Tôi muốn cố gắng sử dụng một subquery để có được id và hạn chế bởi rằng:

SELECT b.id, b.sv, b.description, c.store_id, f.name, e.price 
FROM tbl_watch AS a 
LEFT JOIN tbl_item AS b ON a.item_id = b.id 
LEFT JOIN tbl_storewatch AS c ON c.user_id = '$user_id' 
JOIN tbl_storeflyer AS d ON d.store_id = c.store_id 
JOIN tbl_sale AS e ON e.item_id = a.item_id 
LEFT JOIN tbl_store as f ON d.store_id = f.id 
WHERE a.user_id = '$user_id' 
AND e.flyer_id = d.flyer_id 
AND d.id in (select d.id from d where date_beg = '$s_date') 
ORDER BY b.description ASC 
+0

Cảm ơn bạn đã phản hồi! Các giải pháp này cung cấp các hàng cho tất cả các mục có các mặt hàng bán hàng đang hoạt động (e.item_id = a.item_id VÀ e.flyer_id = d.flyer_id) nhưng tôi cũng cố gắng bao gồm từng mục trong tbl_watch (a) với (b) các trường ngay cả khi chúng không tồn tại trong tbl_sale (e). Vì vậy, tôi sẽ kết thúc với: id, sv, description, NULL, NULL, NULL. Tôi chỉ muốn cho phép 1 hàng với NULL cho mỗi mục. Tôi không chắc chắn làm thế nào để thực hiện điều này. – ridgeback

+0

Chỉ cần làm rõ tôi hy vọng mỗi mục sẽ rơi vào 1 trong 3 trường hợp: 1 - Mục có giá duy nhất. 2 - Mặt hàng có nhiều giá. 3 - Hạng mục không có giá. Nếu 3 xảy ra tôi vẫn muốn một hàng trả về với id mục, sv và mô tả. – ridgeback

+0

không chắc chắn date_beg đây là một trường ngày thực tế, có vẻ như nó đang được sử dụng như một char của một số loại. Tôi không chắc chắn về sự phù hợp với ngày chậm trong MySQL, nhưng tôi sẽ ngạc nhiên. Ngày thường được lưu trữ trong nội bộ như là một dài, và chi phí duy nhất là để bí mật chuỗi đó thành một lâu dài, vì vậy tôi không thuyết phục nó sẽ thêm bất kỳ chi phí nào cả. – PlexQ

1

Tôi nghĩ rằng truy vấn này sẽ cung cấp cho bạn những gì bạn muốn:

select a.id, a.sv, a.description, c.id, c.name, b.price 
    from 
    tbl_item a left outer join tbl_sale b on (a.id=b.item_id) 
     left outer join tbl_storeflyer d on (b.flyer_id=d.flyer_id and d.date_beg = '20120801') 
     left outer join tbl_store c on (d.store_id = c.id) 
     left outer join tbl_storewatch x on (c.id = x.store_id) 
     left outer join tbl_watch y on (a.id = y.item_id); 

với NULLs tham gia, bạn đang có khả năng xảy ra để có một số tham gia trái.Cách thay thế là sử dụng một đoàn, mà với MySQL có thể nhanh hơn:

select a.id, a.sv, a.description, c.id as store_id, c.name, b.price 
    from 
    tbl_item a, 
    tbl_sale b, 
    tbl_storeflyer d, 
    tbl_store c, 
    tbl_storewatch x, 
    tbl_watch y 
    where 
    a.id = b.item_id and 
    b.flyer_id = d.flyer_id and 
    d.store_id = c.id and 
    c.id = x.store_id and 
    a.id = y.item_id and 
    d.date_beg = '20120801' 
union 
select a.id, a.sv, a.description, null as store_id, null as name, null as price 
    from 
    tbl_item a 
    where 
    a.id not in (select b.item_id from tbl_sale b); 

bạn có thể chơi với nửa thứ hai của đoàn là một trái bên ngoài tham gia thay vì một 'không' subquery - phụ thuộc vào cách phiên bản MySQL của bạn tối ưu hóa.

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