2012-08-08 24 views
1

我有一個查詢似乎要花太長時間才能執行。這已經有一段時間了,因爲除了非常簡單的選擇/更新和v.simple連接之外,我已經做了很多事情,所以我在這裏不僅僅是生鏽了!優化我的(簡單)SQL查詢(連接)

SELECT count(distinct r.TAGCODE) 
FROM RAWREADS r 
where r.TAGCODE NOT IN (
    select distinct r.TAGCODE 
    from RAWREADS r, checkpoints c, guards g, INCIDENTITEMS i 
     where r.TAGCODE = c.TAGNO 
     or r.TAGCODE = g.IDTAG 
     or r.TAGCODE = i.IDTAG 
    ); 

內選擇似乎正常工作,如果慢(幾秒鐘),但只要我添加外「算哪裏都不在」我最終不得不殺了我的DB連接 - 因此沒有良好的工作進入應用程序! ;)

我希望上面的查詢清楚了我想要實現的...獲取所有rawread標籤,其中該標籤與checkpoints/guard/incidentitems中的相應列不匹配。

我正在使用Flamebird數據庫服務器(沒有選擇)和FlameRobin運行查詢,如果重要。

在某些時候,我還需要添加一個查詢到外部選擇,以確保我不選擇標籤代碼爲空或「」的任何rawreads。

我已經從out select中刪除了一個「char_length(tagcode)> 0」條件,希望能夠加快速度,但是我認爲我的問題比這個更重要。

回答

3

許多數據庫(也可能是Firebird)無法輕鬆優化NOT IN條件。所以你可能會嘗試將其重寫爲NOT EXTISTS。

另外看看內部選擇,我認爲你加入的方式是產生太多的行。這不是一個真正的加入,但也不是笛卡爾的產品。無論如何,我可以想象,在那裏做一個聯盟也更有效率。

那麼試試這個:

SELECT count(distinct r.TAGCODE) 
FROM RAWREADS r 
where NOT EXISTS (
    select 1 
    from checkpoints c 
    where c.tagno = r.tagcode 
    union all 
    select 1 
    from guards g 
    where g.idtag = r.tagcode 
    union all 
    select 1 
    from INCIDENTITEMS i 
    where i.idtag = r.tagcode); 

如果您對checkpoints(tagno)guards(idtag)incidentitems(idtag)指標應該運行相當快。

+0

+1:可以使用WHERE NOT EXISTS進一步優化(c)而不存在(g)而不存在(i)'? – MatBailie 2012-08-08 13:54:41

+0

@Dems:我認爲這不會有很大的不同。在任何情況下,表中的三個選項都會運行,因爲我不認爲WHERE子句會短路,如果不是必要的話,不會運行其他查詢。但它可能值得一試 – 2012-08-08 13:57:45

+0

感謝馬(!)。我在我的數據庫上試過這個查詢,它返回的速度比我能測量的要快,足夠滿足我的需求(它永遠不會是一個大數據集)。 我現在得去看看工會了! – DaFoot 2012-08-08 14:13:35

2

NOT IN內部的子查詢將被調用RAWREADS中的每一行,因此此查詢運行緩慢。如果你正在運行的程序,傾倒在一個臨時表的子查詢結果,並做內部聯接與臨時表,做負面狀態了TAGCODE

+0

感謝約每行的事 – DaFoot 2012-08-08 14:10:03

1
SELECT count(distinct r.TAGCODE) 
FROM RAWREADS r 
where NOT EXISTS (
    select * 
    from checkpoints c, guards g, INCIDENTITEMS i 
     where r.TAGCODE = c.TAGNO 
     or r.TAGCODE = g.IDTAG 
     or r.TAGCODE = i.IDTAG 
    ); 

如果SQL Server

SELECT count(distinct r.TAGCODE) 
FROM RAWREADS r 
where NOT EXISTS (
    select TOp 1 1 
    from checkpoints c, guards g, INCIDENTITEMS i 
     where r.TAGCODE = c.TAGNO 
     or r.TAGCODE = g.IDTAG 
     or r.TAGCODE = i.IDTAG 
    ); 
+1

'如果SQL Server'解釋TABLEA所有記錄的真快?這個問題指出了Firebird ...另外,SQL Server *不需要'EXISTS'查詢中的'TOP 1'。檢查執行計劃。 – MatBailie 2012-08-08 13:52:38

+1

@Dems:是的,這是一個不會消失的都市傳奇。人們有時也會相信在(NOT)EXISTS查詢中'select 1'會比'select *'更快,這與任何現代DBMS都不一樣(並且可能永遠不會)。 – 2012-08-08 13:59:18

+0

感謝您輸入Ruzbeh,肯定比原始查詢更快,但工會答案似乎是迄今爲止最快的。 – DaFoot 2012-08-08 14:11:46

0

代碼波紋管與Firebird 2.5兼容,速度很快。 我現在無法測試,但這是主意。 它使用CTR來簡化子查詢代碼。

with SQ1 as (
    select distinct r.TAGCODE as TAGCODE 
    from RAWREADS r, checkpoints c, guards g, INCIDENTITEMS i 
     where r.TAGCODE = c.TAGNO 
     or r.TAGCODE = g.IDTAG 
     or r.TAGCODE = i.IDTAG 
) 

SELECT count(distinct r.TAGCODE) 
FROM RAWREADS r 
left join SQ1 on (r.TAGCODE = SQ1.TAGCODE) 
where SQ1.TAGCODE is NULL 
+1

如果你沒有測試過,你怎麼知道它很快? – 2012-08-08 14:55:41

0

在相當多的任何RDBMS以獲得最佳方式優化的NOT IN子句是寫一個LEFT OUTER JOIN使用WHERE子句中發生故障的情況下,像這樣:

SELECT count(distinct r.TAGCODE) 
FROM RAWREADS r 
left outer join checkpoints c on r.TAGCODE = c.TAGNO 
left outer join guards g on r.TAGCODE = g.IDTAG 
left outer join INCIDENTITEMS i on r.TAGCODE=i.IDTAG 
where 
    c.TAGNO is null AND 
    g.IDTAG is null AND 
    i.IDTAG is null 

從一般的角度來看,一個NOT IN子句是這樣的:

select * from TABLEA 
where TABLEA.ID NOT IN (SELECT ID from TABLEB) 

可以成功地轉換在

select TABLEA.* 
from TABLEA 
left outer join TABLEB ON TABLEA.ID=TABLEB.ID 
where TABLEB.ID is null 

如果TABLEB對列ID的索引查詢是檢索從沒有一個對應的TABLEB