2014-06-28 55 views
3

我已經從MSSQL數據庫中獲取一些數據。我不是數據庫所有者,我也沒有能力進行任何更改或添加任何索引或任何內容。我必須與我所擁有的一起工作。 (我認爲數據庫設計師正在使用毒品)高效查詢MSSQL數據庫

DB是通過python腳本訪問的,但是我將在這裏顯示僞代碼,因爲它是重要的SQL。

爲此,有5項數據,我們稱它們爲A,B,C,D和RecipeInstance。在數據庫中,A,B,C和D連接在一起並作爲A @ B @ C @ D存儲在單個列中。 'A @ B @ C @ D'和RecipeInstance之間有一對多關係。

我的2個任務是:

1)由於A,B,C,和d得到所有的食譜

這是很容易的概念,但我的查詢很慢。這是我對此的查詢:

SELECT PDEName as recipe 
FROM RecipeInstance 
WHERE PdeInstanceId 
IN (SELECT DISTINCT PdeInstanceId FROM RecipeTableValue WHERE CellValue 
IN (SELECT DISTINCT PDEName FROM RunInstance WHERE PdeInstanceId 
IN (SELECT PdeInstanceId FROM RunTableValue WHERE CellValue = '[email protected]@[email protected]'))) 

此查詢需要16秒。我真的需要加快速度。我試圖把它分解成4個單獨的查詢,但是他們一起仍然花費了16秒。這些表上沒有有用的索引,我不能創建任何索引。無論如何,任何人都可以想到讓這個更快嗎?

2)由於A,B,C,和配方獲得d

這是更complicaed,因爲沒有關係,從RecipeInstance回到TargetInstance其中d是。以下是我想出了:

select PdeName as TargetPdeName 
FROM TargetInstance 
WHERE PdeName like '[email protected]@[email protected]%' 

# this query returns between 20,000 and 40,000 rows 

foreach TargetPdeName returned from the above query 
    SELECT PDEName as RecipePdeName 
    FROM RecipeInstance 
    WHERE PdeInstanceId 
    IN (SELECT DISTINCT PdeInstanceId FROM RecipeTableValue WHERE CellValue 
    IN (SELECT DISTINCT PDEName FROM RunInstance WHERE PdeInstanceId 
    IN (SELECT PdeInstanceId FROM RunTableValue WHERE CellValue = TargetPdeName))) 

    if RecipePdeName == Recipe: 
     # this is the one we want 
     (a, b, c, d) = TargetPdeName.split('@') 
     return d 

所以這裏的問題顯然是我要運行的查詢數萬,每一個走16秒。任何人都可以看到我如何以有效的方式向後遍歷這種關係?

+0

怎麼樣加入這些表,然後加where子句? part1 – Andrew

+0

無論何時,如果在字符串中使用通配符,您將強制串行數據庫讀取,因此如果您可以分隔或縮小LIKE的結果集「A @ ...」,性能將會提高。在我看來,您可以使用連接來縮小通配符評估的範圍。 –

+0

無論您選擇哪裏A(選擇...)你要求性能明智的麻煩 - 將這些轉換爲等價選擇退出(select * from)。什麼時候不需要子查詢中的disctinct子句 –

回答

1

以下是JOINEXISTS查詢。試試兩個,讓我們知道他們如何運行。

1)

JOIN版本

SELECT DISTINCT reci.PDEName as recipe 
FROM RecipeInstance reci 
JOIN RecipeTableValue rectv ON reci.PdeInstanceId = rectv.PdeInstanceId 
JOIN RunInstance runi ON rectv.CellValue = runi.PDEName 
JOIN RunTableValue runtv ON runi.PdeInstanceId = runtv.PdeInstanceId 
WHERE runtv.CellValue = '[email protected]@[email protected]' 

EXISTS版本

SELECT PDEName as recipe 
FROM RecipeInstance reci 
WHERE EXISTS (
    SELECT * FROM RecipeTableValue rectv 
    WHERE rectv.PdeInstanceId = reci.PdeInstanceId 
    AND EXISTS (
     SELECT * FROM RunInstance runi 
     WHERE runi.PDEName = rectv.CellValue 
     AND EXISTS (
      SELECT * FROM RunTableValue runtv 
      WHERE runi.PdeInstanceId = runtv.PdeInstanceId 
      AND CellValue = '[email protected]@[email protected]'    
     ) 
    ) 
) 

2)編輯:要拆分的@ti.PdeName並提取你需要定義的最後一個值你自己的功能。見How do I split a string so I can access item x

JOIN版本

SELECT DISTINCT ti.PdeName 
FROM RecipeInstance reci 
JOIN RecipeTableValue rectv ON reci.PdeInstanceId = rectv.PdeInstanceId 
JOIN RunInstance runi ON rectv.CellValue = runi.PDEName 
JOIN RunTableValue runtv ON runi.PdeInstanceId = runtv.PdeInstanceId 
JOIN TargetInstance ti ON runtv.CellValue = ti.PdeName 
WHERE reci.PDEName = "MyRecipe" 

EXISTS版本

SELECT ti.PdeName 
FROM TargetInstance ti 
WHERE EXISTS (
    SELECT * FROM RunTableValue runtv 
    WHERE runtv.CellValue = ti.PdeName 
    AND EXISTS (
     SELECT * FROM RunInstance runi 
     WHERE runi.PdeInstanceId = runtv.PdeInstanceId 
     AND EXISTS (
      SELECT * FROM RecipeTableValue rectv 
      WHERE rectv.CellValue = runi.PDEName 
      AND EXISTS (
       SELECT * FROM RecipeInstance reci 
       WHERE reci.PdeInstanceId = rectv.PdeInstanceId 
       AND reci.PDEName = "MyRecipe" 
      ) 
     ) 
    ) 
) 
+0

使用exists子句比join更好,因爲它避免了會發生的重複。原來的帖子是使用不同的條款來殺死這些蠢事。 –

+0

我將不得不在週一嘗試#1,看看它是否會產生正確的結果集和性能。但是對於#2,它沒有考慮到A,B,C或配方中傳遞的信息,並且不會產生我需要的信息。 –

+0

@FuzzyTree是的,這是正確的。這看起來不錯 - 我會在星期一嘗試。謝謝! –