2012-10-22 22 views
5

Nếu tôi có một truy vấn nhưnếu truy vấn phụ không tương quan được lặp lại ở một số vị trí trong truy vấn, nó có thể được lưu trong bộ nhớ cache và kết quả được sử dụng lại không?

SELECT date_trunc('day', assigndate)e, 
     count(CASE WHEN a.assigneeid = 65548 
      AND a.assigneeid IN 
       (SELECT userid 
       FROM groupmembers 
       WHERE groupid = 65553) THEN 1 ELSE NULL END) assigned, 
     count(CASE WHEN a.assigneeid = 65548 
      AND a.completedtime IS NOT NULL 
      AND a.assigneeid IN 
       (SELECT userid 
       FROM groupmembers 
       WHERE groupid = 65553) THEN 1 ELSE NULL END) completed 
FROM ASSIGNMENT a 
WHERE assigndate > CURRENT_TIMESTAMP - interval '20 days' 
GROUP BY date_trunc('day',assigndate); 

Các subquery trong câu hỏi là

SELECT userid 
       FROM groupmembers 
       WHERE groupid = 65553 

sau đó kể từ khi subquery là not co-related với truy vấn phụ huynh, nó sẽ được thực hiện chỉ một lần và kết quả được lưu trữ sẽ đã sử dụng. Nhưng vì truy vấn con có mặt tại 2 vị trí trong truy vấn, sau đó theo số SQL plan, nó được đánh giá hai lần. Có cách nào để cache kết quả của truy vấn con đó và sử dụng nó ở cả hai vị trí không?

Các subquery không thể được chuyển đổi sang một tham gia như là không có trường duy nhất mà trên đó để tham gia (và nó không thể là một điều kiện tham gia, như các tính sẽ trở nên sai rồi)

+1

Dường như bạn có biểu thức dư thừa. Không có vấn đề gì trong việc có mệnh đề "a.assigneeid = 65548" và "a.assigneeid in (subquery)" - cả hai đều đúng hoặc cả hai đều sai. – adhocgeek

+0

Đó chỉ là lý do minh họa (logic sai!) – Daud

Trả lời

10

Bạn có thể sử dụng một bảng phổ biến nhanh (WITH)

with cte as 
(
    SELECT userid FROM groupmembers WHERE groupid = 65553 
) 
SELECT 
    date_trunc('day', assigndate)e, 
    count(CASE WHEN a.assigneeid = 65548 AND a.assigneeid IN 
      (SELECT userid from cte) then 1 else null end) assigned, 
... 
+0

Một biến thể khác của việc này là sử dụng một bảng tạm thời và tham gia vào nó để bạn chỉ thực thi câu lệnh đã cho một lần. – Kuberchaun

+0

Trong SQL Server, điều này không * không * đảm bảo rằng truy vấn phụ sẽ chỉ chạy một lần. Postgres có bảo đảm điều này không? –

+0

@JustBob - sẽ không có cách nào để tham gia bảng tạm thời đó với bảng phân công, và công đoàn sẽ vô điều kiện, tính toán sai số – Daud

1

Bạn nên viết lại truy vấn để loại bỏ các truy vấn con:

SELECT date_trunc('day', assigndate)e, 
     sum(CASE WHEN a.assigneeid = 65548 and gm.userid is not null then 1 else 0 
      end) as assigned, 
     sum(CASE WHEN a.assigneeid = 65548 and a.completedtime IS NOT NULL and gm.userid is not null 
       then 1 else 0 
      end) as completed 
FROM ASSIGNMENT a left outer join 
    (select distinct userid 
     from groupmembers 
     where groupid = 65553 
    ) gm 
    on a.assigneeid = gm.userid 
WHERE assigndate > CURRENT_TIMESTAMP - interval '20 days' 
GROUP BY date_trunc('day',assigndate) 
order by 1 

Nói chung, tôi nghĩ rằng đó là thực hành tốt để kee tham khảo bảng p trong các mệnh đề FROM (hoặc WITH). Có thể khó theo dõi logic của truy vấn con trong mệnh đề SELECT. Trong trường hợp này, các truy vấn phụ rất hài lòng khi chúng thực tế đang cầu xin để được kết hợp thành một câu lệnh duy nhất.

+0

Cảm ơn bạn đã chỉ ra sự giống nhau, nhưng trong kịch bản thực tế, cũng có một mệnh đề đếm với người phê duyệt. Như vậy, tôi không thể tham gia vào việc được chỉ định – Daud

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