优化在同一个表上使用多个左连接的查询

时间:2010-10-11 17:06:21

标签: sql optimization left-join sql-execution-plan

我遇到了一个“太长”的查询。该查询在10个左右的表之间有50多个左连接。为了简要概述数据库模型,连接的表是存储特定数据类型数据的表(例如:date_fields,integer_fields,text_fields等),每个表都有一个值列,一个“datafield”id,和票证ID。查询是基于“票证”及其“数据字段”之间的关联表以编程方式构建的。

join语句如下所示:

...FROM tickets t
LEFT JOIN ticket_text_fields t001 ON(t.id=t001.ticket_id AND t001.textfield_id=7)
...
LEFT JOIN ticket_date_fields t056 ON(t.id=t056.ticket_id AND t056.datafield_id=434)

在查询上使用说明时显示以下内容:

1   SIMPLE   t       ref   idx_dataset_id                   idx_dataset_id  5   const   2871   Using where; Using temporary; Using filesort
1   SIMPLE   t001   ref   idx_ticket_id,idx_datafield_id   idx_ticket_id   5   t.id   5   
... 
1   SIMPLE   t056   ref   idx_ticket_id,idx_datafield_id   idx_ticket_id   5   t.id   8

我可以采用哪个方向来调整此查询?所有索引似乎都已到位。也许应该减少t表(票)行号(2871)。有多少左连接太多了?数据域表是应该只连接一次,然后再查询每个所需的数据吗?

2 个答案:

答案 0 :(得分:7)

您正在使用名为Entity-Attribute-Value的可怕antipattern的变体。您将属性存储在不同的行上,因此如果要重建看起来像传统数据行的内容,则需要为每个属性创建一个连接。

这会创建一个包含50个连接的查询,这并不奇怪。这对于大多数数据库来说有效运行太多了(您还没有确定您正在使用哪个数据库)。最终,您将需要更多属性,并且您可能会超出数据库对其可以执行的连接数的一些体系结构限制。

解决方案是:不要在SQL中重建行。

相反,将属性查询为多行,而不是尝试将它们组合到一行上。

SELECT ... FROM tickets t
INNER JOIN ticket_text_fields f ON t.id=f.ticket_id
WHERE f.textfield_id IN (7, 8, 9, ...)
UNION ALL
SELECT ... FROM tickets t
INNER JOIN ticket_date_fields d ON t.id=d.ticket_id
WHERE d.datafield_id IN (434, 435, 436, ...)

然后,您必须在应用程序中编写一个函数来循环生成的行集,并逐个将属性收集到应用程序空间中的对象中,这样就可以像使用单个实体一样使用它。

答案 1 :(得分:0)

更清晰的查询我会使用这样的东西:

SELECT ... FROM tickets as t  
JOIN ticket_text_fields as txt ON t.id = txt.ticket_id  
JOIN ticket_date_fields as dt ON t.id = dt.ticket_id  
WHERE txt.textfield_id IN (...)
AND dt.datefield_id IN (...)

联接可能是LEFT,但这取决于数据的结构 查询中没有联合,只有两个联接