我被赋予了从MSSQL数据库获取一些数据的任务。我不是数据库所有者,我没有能力进行任何更改或添加任何索引或任何东西。我必须与我所拥有的一起工作。 (我认为数据库设计师是吸毒者。)
通过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 = 'A@B@C@D')))
此查询需要16秒。我真的需要让它更快。我尝试将其分解为4个单独的查询,但他们一起还需要16秒。这些表上没有有用的索引,我也无法创建任何索引。任何人都可以想到让这更快吗?
2)给定A,B,C和配方得到D
这更复杂,因为从RecipeInstance到TargetInstance之间没有任何关系,其中D是。以下是我提出的建议:
select PdeName as TargetPdeName
FROM TargetInstance
WHERE PdeName like 'A@B@C@%'
# 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 :(得分:1)
以下是JOIN
和EXISTS
次查询。试试两者,让我们知道它们是如何运行的。
1)
加入版本
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 = 'A@B@C@D'
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 = 'A@B@C@D'
)
)
)
2)编辑:将ti.PdeName
拆分为@
并提取您需要定义自己的函数的最后一个值。见How do I split a string so I can access item x
加入版本
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"
)
)
)
)