2011-04-06 81 views
3

我目前正在維護大量的SQL查詢。其中一些是通過複製/粘貼操作創建的,然後刪除不必要的字段,有時忘記刪除這些字段來自哪裏的表。在SQL查詢中查找未使用的連接

我正在尋找一個工具(或除了眼睛和大腦以外的任何東西),給定一個SQL查詢,將分析哪些連接表在SELECT部分​​中沒有選擇字段。

你知道這樣的工具嗎?

謝謝

回答

2

打趣的工具可能存在,但它只能保證,如果說所有地方滿足以下條件加盟是正確的

  • 它的左邊或OUTER JOIN或INNER JOIN哪里哪里知道的基數是1-1和...
  • 其在SELECT沒有被引用,HAVING,GROUP BY或WHERE和...
  • 這不是一個JOIN到具有副作用功能...

Probabl y爲什麼在SQL解析器中沒有確定性的警告,我們可以說C#中一個未使用的變量。但是創建一個SQL檢查器可能是值得的,它會查找其中一些條件,並讓用戶知道這裏有可能進行優化。

+0

您還需要確保它不在SUB-SELECT或相關子查詢中引用...... – JNK 2011-04-06 14:58:09

+0

謝謝,我接受您的答案,因爲您提供了更多標準來構建此類工具。 – 2011-04-07 04:52:20

6

只是因爲沒有字段在SELECT中引用,這並不意味着該連接是不查詢和結果的邏輯很重要,如果被刪除的加入可能會改變。

考慮一個簡單的例子:返回誰在2011年

SELECT DISTINCT c.CustomerName 
    FROM Customer c 
     INNER JOIN Sales s 
      ON c.CustomerID = s.CustomerID 
       AND s.SalesDate >= '2011-01-01' 

從銷售表中沒有列在SELECT返回購買的物品所有客戶的名稱,但該連接是在返回正確的關鍵結果集。

底線:我認爲你需要一個人眼/大腦代碼檢查來正確地清理事情。

+1

+1,這是一個非常重要的考慮 – Lamak 2011-04-06 14:37:07

+0

我很清楚這一點,我問這個問題,因爲我知道在我的情況下,聯接只是檢索額外的數據。不管怎麼說,還是要謝謝你。順便說一句,我會很感激,如果你會提供一個答案的原始問題:) – 2011-04-06 20:30:51

+0

@Johann布萊斯:我相信我回答你的原始問題與我的答案的最後一句話,但我會在這裏再次修改它:沒有工具,您需要進行手動代碼審查。 – 2011-04-06 20:34:37

0

下面的函數用count(*)替換所有選擇的字段,第二部分刪除不必要的連接。此函數僅適用於具有別名的表,並且應該針對非常複雜的查詢進行測試,並且如果在聯接條件中存在內部查詢,則該函數將無法工作。

function sql_query_count($sql) { 
     //replace select fields with count(*) 
     $a = true; 
     $b = 0; 
     $first_select = stripos($sql, 'select '); 
     $last_from = 0; 
     $i = 0; 
     while($a){ 
      $i++; 
      $b = stripos($sql, ' from ',$last_from); 
      $c = strripos(substr($sql, $last_from, $b), 'select '); 
      if ($c == $first_select || $c === false || $i>100) $a = false; 
      $last_from = $b+6; 
     }   
     if (stripos($sql, 'order by') !== false) 
      $sql = substr($sql, 0, stripos($sql, 'order by')); 
     $sql1 = 'select count(*) as c ' . substr($sql, $b); 

     //remove unnecessary joins 
     $joins = preg_split("/ join /i", $sql1); 
     $join_count = count($joins); 
     $join_type = ''; 
     if (count($joins)>1){ 
      for ($index = 0; $index < $join_count+2; $index++) { 
       $sql_new = ''; 
       $where = ''; 
       $i = 0; 
       foreach ($joins as $key => $value) { $i++; 
        $parts = preg_split("/ where /i", trim($value)); 
        $value = $parts[0]; 
        unset($parts[0]); 
        $where = implode(' where ', $parts); 
        $occurence_count = 0; 
        if ($i > 1) { 
         $a = explode(' on ', $value); 
         $c = preg_replace('!\s+!', ' ', trim($a[0])); 
         $c = explode(' ', $c); 
         $occurence_count = substr_count($sql1, ' '.$c[1].'.')+substr_count($sql1, '='.$c[1].'.'); 
        } 
        $t = explode(' ', $value); 
        $j = ''; 
        if (trim(strtolower($t[count($t) - 1])) == 'inner'){ 
         $j = 'inner'; 
         unset($t[count($t) - 1]); 
        } else if (trim(strtolower($t[count($t) - 2])).' '.trim(strtolower($t[count($t) - 1])) == 'left outer'){ 
         $j = 'left outer'; 
         unset($t[count($t) - 1]); 
         unset($t[count($t) - 1]); 
        } 
        if ($occurence_count == 0 || $occurence_count > 1) $sql_new.= ' '.$join_type.(($join_type!='')?' join ':'').implode(' ', $t);      
        $join_type = $j; 
       } 
       $sql_new .= ' where '.$where; 
       $sql1 = $sql_new; 
       $joins = preg_split("/ join /i", $sql1); 
      } 
     } 
     return $sql1; 
    } 
0

如上所述,識別冗餘內連接將是一個問題,因爲有時它們對返回的數據產生影響,即使沒有數據實際上是從這些表中選擇。

說的是,識別冗餘的左連接是可能的。我正在使用automatic query optimizer來自動優化SQL查詢。除其他外,它可以識別多餘的左連接。