2014-10-30 60 views
1

早上好。我在Responsys Interact工作,這是一個基於Oracle的電子郵件活動管理類型SAAS產品。我正在創建一個查詢,以基本篩選旨在針對我們的主電子郵件聯繫人列表的特定子集的電子郵件廣告系列的目標列表。下面是我創建了幾個星期前,似乎工作查詢:SQL查詢似乎適用於'AND T1.email_address_ IN(subquery)',但爲'AND T1.email_address_ NOT IN(子查詢)'返回0行'

/* 

Table    Symbolic Name 
CONTACTS_LIST   $A$ 
Engaged    $B$ 
TRANSACTIONS_RAW  $C$ 
TRANSACTION_LINES_RAW $D$ 

-- A Responsys Filter (Engaged) will return only an RIID_, nothing else, according to John @ Responsys....so,....let's join on that to contact list... 

*/ 
SELECT  
DISTINCT $A$.EMAIL_ADDRESS_, 
$A$.RIID_,  
$A$.FIRST_NAME,  
$A$.LAST_NAME,  
$A$.EMAIL_PERMISSION_STATUS_   

FROM 
$A$  
JOIN $B$ ON $B$.RIID_ = $A$.RIID_    
LEFT JOIN $C$ ON $C$.EMAIL_ADDRESS_ = $A$.EMAIL_ADDRESS_  
LEFT JOIN $D$ ON $D$.TRANSACTION_ID = $C$.TRANSACTION_ID   

WHERE 
$A$.EMAIL_DOMAIN_ NOT IN ('none.com', 'noemail.com', 'mailinator.com', 'nomail.com') AND 
/* don't include hp customers */ 
$A$.HP_PLAN_START_DATE IS NULL AND  
$A$.EMAIL_ADDRESS_ NOT IN 
(
    SELECT 
    $C$.EMAIL_ADDRESS_  

    FROM 
    $C$  
    JOIN $D$ ON $D$.TRANSACTION_ID = $C$.TRANSACTION_ID  

    WHERE 
    /* Get only purchase transactions for certain item_id's/SKU's */ 
    ($D$.ITEM_FAMILY_ID IN (3,4,5,8,14,15) OR $D$.ITEM_ID IN (704,769,1893,2808,3013)) AND  
    /* .... within last 60 days (i.e. 2 months) */ 
    $A$.TRANDATE > ADD_MONTHS(CURRENT_TIMESTAMP, -2) 
) 
; 

這似乎是工作,因爲如果我不運行子查詢的查詢,我們得到720K行;如果我加回'AND NOT IN ...'子查詢,我們會得到大約700K行,根據我的用戶瞭解她的數據,這看起來是正確的。我(應該)用NOT IN子查詢處理的是篩選出客戶在過去60天內向我們購買了某些物品的任何電子郵件地址。

所以,現在我需要添加另一個約束。我們仍然不希望在過去60天內進行某些購買的客戶如上所述,但是現在我們也想要排除購買了其他特定項目的客戶,但現在在過去的12個月內。所以,我想我會添加另一個子查詢,如下所示。現在,這已經推出了幾個問題:

  1. 性能 - 查詢,歷時幾分鐘之前運行,現在需要相當幾分鐘運行 - 事實上,它似乎超時....
  2. 所以,我想知道是否有一個問題有兩個子查詢,但在我考慮替代它之前,我決定通過臨時刪除第一個子查詢來測試我的新子查詢,這樣我只有一個類似於上面的子查詢,但新項目= 11,並在過去12個月的邏輯。這樣,查詢在幾分鐘後終於返回,但是零行。
  3. 試圖找出原因,我試圖簡單地將AND NOT IN(子查詢)更改爲AND IN(子查詢),並且工作正常,因爲它按照預期返回了幾千行。
  4. 那麼,爲什麼會使用AND IN(子查詢)「工作」時,相同的SQL,但完全相同的SQL簡單地改爲AND NOT IN(子查詢)返回零行,而不是我所期望的那將是我的700 thousdand加上行,少於幾千個子查詢結果封裝的?
  5. 此外,什麼是最好的,最高效的方式來完成我想要做的事情,這是通過在一個日期範圍內進行的一些購買過濾,以及在不同日期範圍內進行的一些其他購買?

下面是修改的版本:

SELECT  
DISTINCT $A$.EMAIL_ADDRESS_, 
$A$.RIID_,  
$A$.FIRST_NAME,  
$A$.LAST_NAME,  
$A$.EMAIL_PERMISSION_STATUS_   

FROM 
$A$  
JOIN $B$ ON $B$.RIID_ = $A$.RIID_    
LEFT JOIN $C$ ON $C$.EMAIL_ADDRESS_ = $A$.EMAIL_ADDRESS_  
LEFT JOIN $D$ ON $D$.TRANSACTION_ID = $C$.TRANSACTION_ID   

WHERE 
$A$.EMAIL_DOMAIN_ NOT IN ('none.com', 'noemail.com', 'mailinator.com', 'nomail.com') AND 
/* don't include hp customers */ 
$A$.HP_PLAN_START_DATE IS NULL AND 
$A$.EMAIL_ADDRESS_ NOT IN 
(
    SELECT 
    $C$.EMAIL_ADDRESS_  

    FROM 
    $C$  
    JOIN $D$ ON $D$.TRANSACTION_ID = $C$.TRANSACTION_ID  

    WHERE 
    /* Get only purchase transactions for certain item_id's/SKU's */ 
    ($D$.ITEM_FAMILY_ID IN (3,4,5,8,14,15) OR $D$.ITEM_ID IN (704,769,1893,2808,3013)) AND 
    /* .... within last 60 days (i.e. 2 months) */ 
    $C$.TRANDATE > ADD_MONTHS(CURRENT_TIMESTAMP, -2)  
) 
AND 
$A$.EMAIL_ADDRESS_ NOT IN 
(
    /* get purchase transactions for another type of item within last year */ 
    SELECT 
    $C$.EMAIL_ADDRESS_ 
    FROM 
    $C$  
    JOIN $D$ ON $D$.TRANSACTION_ID = $C$.TRANSACTION_ID 
    WHERE 
    $D$.ITEM_FAMILY_ID = 11 AND $C$.TRANDATE > ADD_MONTHS(CURRENT_TIMESTAMP, -12) 
) 
; 

感謝您的任何想法/見解。我可能會錯過或錯誤地記住一些基本的SQL概念 - 如果有的話,請幫助我!此外,Responsys Interact運行在Oracle之上 - 這是一款Oracle產品 - 但我不知道哪種版本/風格。謝謝!

+0

您確實需要查看各種查詢的執行計劃,以查看正在使用的連接順序,索引和過濾器。除非您可以針對基礎表運行查詢,否則這可能會在中間層棘手。我猜''trandate'對於12個月的範圍是不夠有選擇性的,並且'item_id'或'item_family_id'沒有編入索引(你是否在新過濾器中使用了正確的那個?)。但是......你已經離開了加入'$ D $',那麼你需要再次加入子查詢嗎? – 2014-10-30 16:51:05

+0

感謝您的回覆,Alex。在12個月的範圍內,你的關於trandate沒有足夠選擇性的觀點實際上是我第一次想到當我第一次運行修改後的查詢。但瞭解這些數據,我很確定我們在過去的12個月內購買了這個產品。因此,爲了測試這一點,我擺脫了第一個原始子查詢,只關注新子查詢,並將「NOT IN」更改爲「IN」,以確定在過去的12個月內是否真的會讓零客戶購買該項目... – JMoll 2014-10-30 17:03:02

+0

...(繼續上面的評論)這返回了總計2683行,符合預期。但是當我把它從'IN'改回'NOT IN'時,我得到零行。我預計會得到700k減去2683 ....所以這是我沒有看到正確的所有這些...... – JMoll 2014-10-30 17:03:33

回答

0

看起來像我的新子查詢的問題是由於缺乏索引性能差。感謝Alex Poole的評論,我查看了Responsys,並且有一個獲得'解釋'類型分析的工具,它正在發出警告,並建議我構建一些索引。找到了在數據源上做到這一點的方法,回到瞭解釋中,它說:「查詢應該運行而不會給系統帶來不必要的負擔」。雖然它仍然運行了好幾分鐘,但它終於回來了,接近預期的行數。

現在,我正在處理另一半的問題,現在除了第一個原始子查詢之外,現在還包含第二個子查詢....

0

好吧,在進一步的測試/分析和提煉我的計算器搜索critieria,回答我的問題處理的IN的主要部分與NOT IN可以在這裏找到:SQL "select where not in subquery" returns no results

我的表現受到幫助使用Responsys的類似於解釋的功能並添加了一些索引,但是當我這樣做時,我恰好在我的子查詢的WHERE子句中添加了一點額外的SQL ....當我刪除該索引時,即使在創建索引後,我仍然返回零行。這是因爲事實證明,我對這個額外的子查詢感興趣的項目族ID至少有一個事務行對於電子郵件地址具有空值。正如在上面的鏈接中進一步解釋的那樣,當使用NOT IN時,只要涉及空值,SQL就不能確切地說它不是IN,因爲你無法真正地將它與null比較,所以只要你有一個空,子查詢將評估'假',因此零行。當使用IN時,即使存在空值,如果您得到一個正匹配,那麼這是一個匹配,所以子查詢返回'true',所以這就是爲什麼您會得到具有IN的行,但不具有NOT IN 。我還沒有意識到,我們的一些交易數據可能有空電子郵件地址 - 現在我知道了,所以我只是在where子句中添加了一個不爲空的電子郵件地址,現在一切都很好。