SQL查询、完全联接、性能

SQL查询、完全联接、性能,sql,sql-server,performance,Sql,Sql Server,Performance,我有一个人的属性表,同一个人最多可以有18个不同的属性。该表如下所示: Personid, Propertytype, Propertyvalue, Propertyname 我想使用完全联接执行SQL查询,以将一个人的所有属性都放到结果集中的一行中。 我做过这样的查询,但我认为如果你考虑响应时间/性能的话,它不是最佳的。 在数据库中,我有超过1200万人,因此有很多数据行 我的SQL查询: SELECT DISTINCT (Information.PersonID), f.PersonN

我有一个人的属性表,同一个人最多可以有18个不同的属性。该表如下所示:

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的使用看起来确实有点奇怪,但它确实起到了作用。