优化具有多个连接的SQL查询

时间:2012-05-31 09:36:41

标签: sql sql-server join sql-server-2008-r2 query-optimization

我的数据库中有以下表格,我无法更改或修改。我保持Log表简单,但LogDetail与我的数据库中的相同。

日志表

 Id  User Department Service     Method

 21  John Sales      UserService GetUser

LogDetail表

Id LogRef ParamName  ParamValue

30 21     FirstName  Adam
31 21     LastName   Smith     
32 21     Age        35
33 21     Gender     M

现在,我正在使用以下查询来搜索谁(Adam,Smith,35,M)

SELECT 
L.*, D1.ParamName, D2.ParamName, D3.ParamName, D4.ParamName
FROM Log as L
INNER JOIN LogDetail as D1 on L.Id = D1.LogRef
INNER JOIN LogDetail as D2 on L.Id = D2.LogRef
INNER JOIN LogDetail as D3 on L.Id = D3.LogRef
INNER JOIN LogDetail as D4 on L.Id = D4.LogRef
WHERE
D1.ParamName='FirstName' and D1.ParamValue='Adam' and
D2.ParamName='LastName' and D2.ParamValue='Smith' and
D3.ParamName='Age' and D3.ParamValue=35 and
D4.ParamName='Gender' and D4.ParamValue='M'

有更好的方法吗?

3 个答案:

答案 0 :(得分:6)

当您使用EAV架构(基本上是键值对)

时会发生这种情况

除了为(ParamName, ParamValue) LogDetail添加索引外,您可以做的不多。这假设聚集索引保持为LogRef

答案 1 :(得分:1)

您只能对join子句中使用的字段使用Index

答案 2 :(得分:1)

通过创建一个将键值对聚合成更有用的东西的视图来简化查询的一种方法:

CREATE VIEW ViewLogUsers
AS
SELECT UFN.LogRef, UFN.ParamName AS FirstName, ULN.ParamName AS LastName, UAG.ParamName AS Age, UGE.ParamName AS Gender
FROM LogDetail AS UFN
INNER JOIN LogDetail AS ULN ON UFN.LogRef = ULN.LogRef
INNER JOIN LogDetail AS UAG ON UFN.LogRef = UAG.LogRef
INNER JOIN LogDetail AS UGE ON UFN.LogRef = UGE.LogRef
WHERE UFN.ParamName = 'Firstname' AND ULN.ParamName = 'LastName' AND UAG.ParamName = 'Age' AND UGE.ParamName = 'Gender'
GO

然后您的原始查询变为:

SELECT 
L.*, D1.FirstName, D1.LastName, D1.Age, D1.Gender
FROM Log as L
INNER JOIN ViewLogUsers as D1 on L.Id = D1.LogRef
WHERE D1.FirstName = 'Adam' AND D1.LastName = 'Smith' AND D1.Age = '35' AND D1.Gender = 'M'

如果您使用与视图相同的结构制作表格,您的表现仍然会更差(尽管如果您能够使用索引视图,它会有所帮助),但它会更容易至少使用。