如何在具有大量数据的表上使用自联接编写查询?

时间:2012-05-22 14:48:13

标签: sql sql-server sql-server-2008 tsql sql-server-2005

使用以下表格结构:

表1:客户

CustID(primary key)  |  CustName(indexed)
----------------------------------
C1                       Cust1
C2                       Cust2
.                        Cust3
.                        Cust.
.                        Cust.
C10000                   Cust10000

表2: CustomFields

FieldID (primary key) |  ID (indexed)                | FieldValue
---------------------------------------------------------------------
1                        C1                              Test 
2                        C2                              Test 
3                        C3                              Test 
4                        C4                              Test 
.                        .                               Test 
.                        .                               Test 
few millions             Z1                              Test   

"ID" column is indexed.

尝试输出以下内容;

CustID  |  Field 1  |  Field 2 | Field 3 | .... | Field N
----------------------------------------------------------

我尝试编写像

这样的查询
Select 
    CustID, A1.FieldValue as [Field 1], A2.FieldValue as [Field 2]
from 
    Customers 
left outer join 
    CustomFields A1 on Customers.custID = A1.ID
left outer join 
    CustomFields A2 on Customers.custID = A2.ID
left outer join 
    CustomFields An on Customers.custID = An.ID
where 
    custName like 'C%'

由于CustomFields表包含几百万条记录,因此上述查询效果不佳。现在需要大约10-12秒(500个客户和6个领域)

我认为左外连接在这里增加了时间。任何解决问题的想法都会有所帮助吗?

平台:SQL Server 2005

更新:

CustomFields表是一个通用表,它可以包含任何其他实体(供应商,项目等)的字段。

4 个答案:

答案 0 :(得分:1)

您是否尝试过使用数据库引擎优化顾问分析查询?没有保证,但它可能会提供一两个有用的建议。

enter image description here

答案 1 :(得分:0)

你的查询是完全合理的。但是,数据库结构已关闭。您应该为客户ID和字段ID分别创建一个列。编写查询的方式,您将获得与另一个表中的字段一样多的CustId行。

它们不应合并为一列。我希望联接看起来像:

left outer join
CustomerFields cfn
on cfn.CustId = Customers.CustId and
   cfn.FieldNum = <n>

另一种可能性是性能命中是您第一次运行查询。如果你有足够的内存,那么它第二次可能运行得更快 - 因为fields表在内存中。

为了记录,我对“喜欢”有历史偏见,相信它会导致性能问题。这可能没有帮助,但您可以尝试:

where left(CustName, 1) = 'C'

答案 2 :(得分:0)

    SELECT  Pvt.ID, 
            Customers.CustName, 
            Pvt.[1] AS Field1, 
            Pvt.[2] AS Field2, 
            Pvt.[3] AS Field3, 
            Pvt.[4] AS Field4, 
            Pvt.[5] AS Field5,
            ...
    FROM (
            SELECT ID, FieldID, FieldValue
            FROM CustomFields) AS p
            PIVOT (
                MIN (FieldValue)
                FOR FieldID IN ([1], [2], [3], [4], [5], ... )
        ) AS pvt
    inner join Customers ON Customers.CustID = pvt.ID

答案 3 :(得分:0)

您可以使用单个联接来获取自定义字段,并使用聚合函数来转置它们。这样,与表CustomFields的连接只进行一次。

喜欢这个。

SELECT
  Customers.CustID,
  MAX(CASE WHEN CF.FieldID = 1 THEN CF.FieldValue ELSE NULL END) AS Field1,
  MAX(CASE WHEN CF.FieldID = 2 THEN CF.FieldValue ELSE NULL END) AS Field2,
  MAX(CASE WHEN CF.FieldID = 3 THEN CF.FieldValue ELSE NULL END) AS Field3,
  MAX(CASE WHEN CF.FieldID = 4 THEN CF.FieldValue ELSE NULL END) AS Field4
  -- Add more...

  FROM Customers 

  LEFT OUTER JOIN CustomFields CF
  ON CF.ID = Customers.CustID

  WHERE Customers.CustName like 'C%'

  GROUP BY Customers.CustID