2010-10-21 47 views
5

Tôi có hai bảng - incoming tours(id,name)incoming_tours_cities(id_parrent, id_city)Cần giúp đỡ trong việc tối ưu hóa truy vấn

id trong bảng đầu tiên là duy nhất, và cho mỗi hàng độc đáo từ bảng đầu tiên có danh sách các id_city - s trong bảng thứ hai (tức là id_parrent trong bảng thứ hai là bằng id từ bảng đầu tiên)

Ví dụ

incoming_tours

|--id--|------name-----| 
|---1--|---first_tour--| 
|---2--|--second_tour--| 
|---3--|--thirth_tour--| 
|---4--|--hourth_tour--| 

incoming_tours_cities

|-id_parrent-|-id_city-| 
|------1-----|---4-----| 
|------1-----|---5-----| 
|------1-----|---27----| 
|------1-----|---74----| 
|------2-----|---1-----| 
|------2-----|---5-----| 
........................ 

Điều đó có nghĩa rằng first_tour có danh sách các thành phố - ("4","5","27","74")

second_tour có danh sách các thành phố - ("1","5")


Giả sử tôi có hai giá trị - 474:

Bây giờ, tôi cần phải nhận tất cả các hàng từ bảng đầu tiên, trong đó cả hai giá trị đều nằm trong danh sách các thành phố. tức là nó phải trả lại chỉ first_tour (vì 4 và 74 trong đó là danh sách các thành phố)

Vì vậy, tôi đã viết các truy vấn sau

SELECT t.name 
FROM `incoming_tours` t 
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id 
AND tc0.id_city = '4' 
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id 
AND tc1.id_city = '74' 

Và đó hoạt động tốt.

Nhưng tôi tạo truy vấn động và khi số lượng kết nối lớn (khoảng 15) truy vấn sẽ chậm lại.

tức là khi tôi cố gắng để chạy

SELECT t.name 
FROM `incoming_tours` t 
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id 
AND tc0.id_city = '4' 
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id 
AND tc1.id_city = '74' 
......................................................... 
JOIN `incoming_tours_cities` tc15 ON tc15.id_parrent = t.id 
AND tc15.id_city = 'some_value' 

truy vấn chạy trong 45s (mặc dù trên tôi đặt chỉ số trong bảng)

gì tôi có thể làm, để optimaze nó?

Cảm ơn nhiều

+0

bạn tham gia cùng một bảng 14 lần? –

+0

CÓ, vì tôi phải kiểm tra 14 giá trị. – Simon

+0

nếu có cách khác để đạt hiệu quả tương tự, vui lòng cho tôi biết cách – Simon

Trả lời

6
SELECT t.name 
FROM incoming_tours t INNER JOIN 
    (SELECT id_parrent 
    FROM incoming_tours_cities 
    WHERE id IN (4, 74) 
    GROUP BY id_parrent 
    HAVING count(id_city) = 2) resultset 
    ON resultset.id_parrent = t.id 

Nhưng bạn cần thay đổi số tổng thành phố đếm.

+1

Bạn chỉ lấy các parent_ids khớp với danh sách thành phố của bạn hai lần. Bằng cách đó bạn biết rằng họ có cả hai thành phố. –

+1

Ồ, và thay thế 'id' bằng' id_city' –

+0

để tôi thử nghiệm ... – Simon

0

Chỉ cần gợi ý. Nếu bạn sử dụng toán tử IN trong mệnh đề WHERE, bạn có thể hy vọng rằng toán tử ngắn hạn AND có thể xóa JOIN s không cần thiết trong khi thực hiện các chuyến tham quan không tôn trọng ràng buộc.

0

Có vẻ như một cách kỳ lạ để làm truy vấn rằng, đây

SELECT t.name FROM `incoming_tours` as t WHERE t.id IN (SELECT id_parrent FROM `incoming_tours_cities` as tc WHERE tc.id_city IN ('4','74')); 

tôi nghĩ nào đó, nhưng không được kiểm tra ...

EDIT: Thêm bảng bí danh để sub-query

+0

điều này sẽ không hoạt động, vì tôi cần ** tất cả giá trị ** để khớp, nhưng khi bạn viết 'in' bằng' hoặc', không phải ' và' xác minh câu lệnh. – Simon

+0

tức là sau khi chạy truy vấn của bạn với các giá trị của ('" 5 "', '" 74 "'), bạn sẽ nhận được cả hai 'first_tour' và' second_tour', nhưng chúng ta chỉ cần đầu tiên. – Simon

+0

Tôi đã chạy truy vấn của mình sau khi tạo lại các bảng từ ví dụ và chỉ trả về first_tour. – pharalia

1

Tôi khá chắc chắn rằng công trình này, nhưng ít hơn rất nhiều chắc chắn rằng nó là tối ưu.

SELECT * FROM incoming_tours 
WHERE 
id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=4) 
AND id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=74) 
... 
AND id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=some_value) 
+0

tôi đã thử nghiệm nó đã có, nó mach chậm hơn so với tham gia – Simon

+0

Tôi bây giờ đã có một cái nhìn vào thời gian thực hiện truy vấn, quá. Nó dường như không chậm hơn nhiều ở các giá trị điều kiện thấp hơn, nhưng dường như có nhiều truy vấn con 'SELECT' nhanh hơn nhiều để có cùng số điều kiện' JOIN' cho số lượng điều kiện cao hơn. – Aether

2
SELECT name 
FROM (
     SELECT DISTINCT(incoming_tours.name) AS name, 
      COUNT(incoming_tours_cities.id_city) AS c 
     FROM incoming_tours 
      JOIN incoming_tours_cities 
       ON incoming_tours.id=incoming_tours_cities.id_parrent 
     WHERE incoming_tours_cities.id_city IN(4,74) 
      HAVING c=2 
    ) t1; 

Bạn sẽ phải thay đổi c=2 để bất cứ đếm id_city bạn đang tìm kiếm, nhưng kể từ khi bạn tạo ra truy vấn động, đó không phải là một vấn đề.

+0

Tôi không chắc chắn điều này là chính xác. Bạn không cần một 'GROUPBY'? –

+0

Không có vẻ như nó - Tôi đã thử nghiệm nó và nó hoạt động tốt. – Narf

0

Tôi đã viết truy vấn này bằng CTE và nó bao gồm dữ liệu thử nghiệm trong truy vấn. Bạn sẽ cần phải sửa đổi nó để nó truy vấn các bảng thực thay thế. Không chắc chắn cách thức hoạt động trên tập dữ liệu lớn ...

Declare @numCities int = 2 

;with incoming_tours(id, name) AS 
(
    select 1, 'first_tour' union all 
    select 2, 'second_tour' union all 
    select 3, 'third_tour' union all 
    select 4, 'fourth_tour' 
) 
, incoming_tours_cities(id_parent, id_city) AS 
(
    select 1, 4 union all 
    select 1, 5 union all 
    select 1, 27 union all 
    select 1, 74 union all 
    select 2, 1 union all 
    select 2, 5 
) 
, cityIds(id_city) AS 
( 
    select 4 
    union all select 5 
    /* Add all city ids you need to check in this table */ 
) 
, common_cities(id_city, tour_id, tour_name) AS 
(
    select c.id_city, it.id, it.name 
    from cityIds C, Incoming_tours_cities tc, incoming_tours it 
    where C.id_city = tc.id_city 
    and tc.id_parent = it.id 
) 
, tours_with_all_cities(id_city) As 
(
    select tour_id from common_cities 
    group by tour_id 
    having COUNT(id_city) = @numCities 
) 
select it.name from incoming_tours it, tours_with_all_cities tic 
where it.id = tic.id_city 
Các vấn đề liên quan