SQL查询、完全联接、性能
我有一个人的属性表,同一个人最多可以有18个不同的属性。该表如下所示:SQL查询、完全联接、性能,sql,sql-server,performance,Sql,Sql Server,Performance,我有一个人的属性表,同一个人最多可以有18个不同的属性。该表如下所示: Personid, Propertytype, Propertyvalue, Propertyname 我想使用完全联接执行SQL查询,以将一个人的所有属性都放到结果集中的一行中。 我做过这样的查询,但我认为如果你考虑响应时间/性能的话,它不是最佳的。 在数据库中,我有超过1200万人,因此有很多数据行 我的SQL查询: SELECT DISTINCT (Information.PersonID), f.PersonN
Personid, Propertytype, Propertyvalue, Propertyname
我想使用完全联接执行SQL查询,以将一个人的所有属性都放到结果集中的一行中。
我做过这样的查询,但我认为如果你考虑响应时间/性能的话,它不是最佳的。
在数据库中,我有超过1200万人,因此有很多数据行
我的SQL查询:
SELECT DISTINCT (Information.PersonID),
f.PersonName,
f1.Property AS 'P1',
f1.PropertyValue AS 'P1Value',
f1.PropertyName AS 'P1Name',
f2.Property AS 'P2',
f2.PropertyValue AS 'P2Value',
f2.PropertyName AS 'P2Name',
......
FROM Person f
FULL JOIN (
SELECT
PersonName,
Property,
PropertyValue,
PropertyName
FROM Person WHERE Property='P1'
GROUP BY PersonName, Property, PropertyValue, PropertyName
) f1 ON f.PersonName=f1.PersonName
FULL JOIN (
SELECT PersonName,
Property,
PropertyValue,
PropertyName
FROM Person WHERE Property='P2'
GROUP BY PersonName, Property, PropertyValue, PropertyName
) f2 ON f.PersonName=f2.PersonName
....
INNER JOIN Information ON f.PersonName = Information.Name
如何更有效地执行此查询,有什么建议吗?您可以选择所需的行,然后将行旋转到列中,其中一种方法是在select for each id中使用case语句。 这将减少对person表的扫描次数。因为您只能对该表进行一次扫描 e、 g:
您可以选择所需的行,然后将行转为列,其中一种方法是在select for each id中使用case语句。 这将减少对person表的扫描次数。因为您只能对该表进行一次扫描 e、 g:
尝试使用PIVOT。此处链接到BOL 它将一列中的多行转换为一行中的多列,例如
Person1, Left-Handed
Person1, Blue Eyes
Person2, Right-Handed
Person2, Brown Eyes
转向:
Person1, Left-Handed, Blue Eyes
Person2, Right-Handed, Brown Eyes
尝试使用PIVOT。此处链接到BOL 它将一列中的多行转换为一行中的多列,例如
Person1, Left-Handed
Person1, Blue Eyes
Person2, Right-Handed
Person2, Brown Eyes
转向:
Person1, Left-Handed, Blue Eyes
Person2, Right-Handed, Brown Eyes
我会尝试使用PIVOT,或者:
SELECT
i.PersonID
, i.PersonName
, f1.Property AS 'P1'
, f1.PropertyValue AS 'P1Value'
, f1.PropertyName AS 'P1Name'
, f2.Property AS 'P2'
, f2.PropertyValue AS 'P2Value'
, f2.PropertyName AS 'P2Name'
......
FROM
Information AS i
LEFT JOIN Person AS f1
ON f1.PersonID = i.PersonId
AND f1.Property = 'P1'
LEFT JOIN Person AS f2
ON f2.PersonID = i.PersonId
AND f2.Property = 'P2'
......
我会尝试使用PIVOT,或者:
SELECT
i.PersonID
, i.PersonName
, f1.Property AS 'P1'
, f1.PropertyValue AS 'P1Value'
, f1.PropertyName AS 'P1Name'
, f2.Property AS 'P2'
, f2.PropertyValue AS 'P2Value'
, f2.PropertyName AS 'P2Name'
......
FROM
Information AS i
LEFT JOIN Person AS f1
ON f1.PersonID = i.PersonId
AND f1.Property = 'P1'
LEFT JOIN Person AS f2
ON f2.PersonID = i.PersonId
AND f2.Property = 'P2'
......
这可以通过枢轴和取消PIVOT操作的组合来完成
;WITH a AS
(
SELECT PersonName
, Property [Prefix]
, Property [ ]
, PropertyValue [Value]
, PropertyName [Name]
FROM dbo.Person
)
, c AS
(
SELECT b.PersonName, RTRIM(b.Prefix + b.Suffix) Field, b.Data
FROM a
UNPIVOT (Data FOR Suffix IN ([ ], [Value], [Name])) b
)
SELECT d.*
FROM c PIVOT (MIN(Data) FOR Field IN
(
[P1], [P1Value], [P1Name]
, [P2], [P2Value], [P2Name]
, [P3], [P3Value], [P3Name]
)) d
这可以通过枢轴和取消PIVOT操作的组合来完成
;WITH a AS
(
SELECT PersonName
, Property [Prefix]
, Property [ ]
, PropertyValue [Value]
, PropertyName [Name]
FROM dbo.Person
)
, c AS
(
SELECT b.PersonName, RTRIM(b.Prefix + b.Suffix) Field, b.Data
FROM a
UNPIVOT (Data FOR Suffix IN ([ ], [Value], [Name])) b
)
SELECT d.*
FROM c PIVOT (MIN(Data) FOR Field IN
(
[P1], [P1Value], [P1Name]
, [P2], [P2Value], [P2Name]
, [P3], [P3Value], [P3Name]
)) d
表上有什么索引?还请添加表结构字段和类型您使用的是什么、SQL Server、MySQL、DB2等?表、Person和Information的表结构。Person表中的所有列都具有数据类型nvarchar50。在表信息中,PersonId是二进制16,名称是NVARCHAR100是否值得质疑为什么需要对数据集进行反规范化?让我吃惊的是,您已经拥有了适合SQL处理的数据格式,并且客户端应用程序可以轻松地在使用时对这些数据进行透视/反规范化。是什么要求促使您在SQL中这样做?表上有哪些索引?还请添加表结构字段和类型您使用的是什么、SQL Server、MySQL、DB2等?表、Person和Information的表结构。Person表中的所有列都具有数据类型nvarchar50。在表信息中,PersonId是二进制16,名称是NVARCHAR100是否值得质疑为什么需要对数据集进行反规范化?让我吃惊的是,您已经拥有了适合SQL处理的数据格式,并且客户端应用程序可以轻松地在使用时对这些数据进行透视/反规范化。是什么要求促使您在SQL中执行此操作?好的,但这是否比我的解决方案更快…似乎是相同的响应时间!?我甚至不相信OP的回答中的子问题是必要的。每次直接左键连接到Person?您还没有告诉我们您在表上的索引。@Dems:您是对的。我昨天做了一件类似的事情,需要在子查询中加入一个分组。现在更正。我在Person表和信息表上没有索引,我在PersonID上有索引。好的,但这比我的解决方案快吗…似乎是相同的响应时间!?我甚至不相信OP的回答中的子问题是必要的。每次直接左键连接到Person?您还没有告诉我们您在表上的索引。@Dems:您是对的。我昨天做了一件类似的事情,需要在子查询中加入一个分组。现在更正。我在Person表上没有索引,在PersonID上有索引的信息表。是否可以透视2列?是否可以透视2列?如果属性不重复,这似乎是执行所需任务的最快方法,但是这个解决方案比大多数其他解决方案都能更好地处理这个问题。这似乎是最快的,非常感谢!但是你能给我解释一下为什么要使用max吗?内部sql为每个属性值返回一行,例如记录1:kevin 100记录2:kevin 01 00记录3:kevin 01 01 0 max然后返回一行,例如kevin 1 1 1 0,但每个人只有一个P1属性。我只在同一问题有多个值时才使用max…如果我不使用max,我想我无法分组…这就是为什么?抱歉,但我一开始不明白:没错,我想max的使用看起来有点奇怪,但它确实起到了作用。如果属性不重复,这似乎是完成所需任务的最快方法,但此解决方案比大多数其他解决方案处理得更好这似乎是最快的,非常感谢!但是你能解释一下为什么要使用max吗?内部sql为每个属性值返回一行,例如记录1:kevin 1:0 0记录2:kevin
0 1 0 0 0记录3:kevin 0 0 1 0最大值然后返回一行,例如kevin 1 1 0 0,但每个人只有一个P1属性。我只在同一问题有多个值时才使用max…如果我不使用max,我想我无法分组…这就是为什么?抱歉,但我一开始不明白:没错,我想max的使用看起来确实有点奇怪,但它确实起到了作用。