如何减少此查询中已连接表的数量?

时间:2013-07-18 18:25:14

标签: mysql sql pivot-table entity-attribute-value

CREATE TABLE Attributes (
    id      VARCHAR(40),
    type    VARCHAR(16),
    data    VARCHAR(2048),
    PRIMARY KEY(id,type)
);

这是我尝试运行的查询的一般格式。一般的想法是'对象'具有唯一的ID,然后有一个键/值对,如javascript对象。

SELECT a1.id, a1.data, a2.data, a3.data, a4.data, a6.data
    FROM Attributes a1, Attributes a2, Attributes a3, Attributes a4, Attributes a5
    LEFT JOIN Attributes a6 ON (a6.id=a5.id AND a6.type = 'Foreign Id')
        WHERE a1.id=a2.id
            AND a1.id=a3.id
            AND a1.id=a4.id
            AND a1.id=a5.id
            AND a1.type = 'First Name' 
            AND a2.type = 'Middle Name' 
            AND a3.type = 'Last Name'
            AND a4.type = 'Timestamp'
            AND a5.type = 'Count'
            AND a5.data = 'MY_ID'

在此查询中,'Foreign Id'是可选属性。问题是我得到了

  

SELECT将检查超过MAX_JOIN_SIZE行;检查你的   WHERE并使用SET SQL_BIG_SELECTS = 1或SET MAX_JOIN_SIZE =#if   选择没问题。

我意识到我可以这样说,但警告让我担心这个查询非常低效。有没有更好的方法来制定查询?

2 个答案:

答案 0 :(得分:5)

由于主键密钥为ID, Type,您可以使用聚合函数并确保查询仍然是确定性的,将查询减少为0个连接:

SELECT  a.ID,
        MAX(CASE WHEN a.type = 'First Name' THEN a.Data END) AS FirstName,
        MAX(CASE WHEN a.type = 'Last Name' THEN a.Data END) AS LastName,
        MAX(CASE WHEN a.type = 'Timestamp' THEN a.Data END) AS `Timestamp`,
        MAX(CASE WHEN a.type = 'Count' THEN a.Data END) AS `Count`,
        MAX(CASE WHEN a.type = 'MY_ID' THEN a.Data END) AS MY_ID,
        MAX(CASE WHEN a.Type = 'Foreign Id' THEN a.Data END) AS ForeignId
FROM    Attributes a
GROUP BY a.ID;

值得注意的是,实体 - 属性 - 值模型是一个SQL反模式,你可以更好地规范化数据以将属性存储为列,而不是必须使用上面的查询将行转换为列。

修改

要根据属性添加过滤器,请使用HAVING子句:

SELECT  a.ID,
        MAX(CASE WHEN a.type = 'First Name' THEN a.Data END) AS FirstName,
        MAX(CASE WHEN a.type = 'Last Name' THEN a.Data END) AS LastName,
        MAX(CASE WHEN a.type = 'Timestamp' THEN a.Data END) AS `Timestamp`,
        MAX(CASE WHEN a.type = 'Count' THEN a.Data END) AS `Count`,
        MAX(CASE WHEN a.type = 'MY_ID' THEN a.Data END) AS MY_ID,
        MAX(CASE WHEN a.Type = 'Foreign Id' THEN a.Data END) AS ForeignId
FROM    Attributes a
GROUP BY a.ID
HAVING MAX(CASE WHEN a.type = 'MY_ID' THEN a.Data END) = 1;

答案 1 :(得分:0)

您的属性表很窄,但有很多行。并且您将要么进行一系列自连接,要么使用group by a.id进行查询并使用聚合函数。后一种方法消除了连接,但仍然会产生很多行。

我认为更好的选择是对数据模型进行非规范化。这将涉及创建一个包含“First Name”列,“Middle Name”列等的表。然后,与ID关联的各种属性都在同一行。最终会得到一个更宽的表,但行数和连接数要少得多。