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

Sql 优化在同一个表上使用多个左联接的查询,sql,optimization,left-join,sql-execution-plan,Sql,Optimization,Left Join,Sql Execution Plan,我遇到了一个耗时“太长”的问题。该查询在大约10个表之间有50多个左联接。为了简要概述数据库模型,所连接的表是存储特定数据类型(例如:日期字段、整数字段、文本字段等)的数据的表,每个表都有一列值、“数据字段”id和票证id。查询是基于“票证”及其子项之间的关联表以编程方式构建的“数据字段” join语句如下所示: ...FROM tickets t LEFT JOIN ticket_text_fields t001 ON(t.id=t001.ticket_id AND t001.textfiel

我遇到了一个耗时“太长”的问题。该查询在大约10个表之间有50多个左联接。为了简要概述数据库模型,所连接的表是存储特定数据类型(例如:日期字段、整数字段、文本字段等)的数据的表,每个表都有一列值、“数据字段”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
在查询中使用explain时,显示以下内容:

...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)应该减少。左联接的数量太多了吗?是否应该只联接一次数据字段表,然后查询每个表中所需的数据?

您使用的是一种称为实体属性值的变体。您将属性存储在单独的行上,因此如果您想重建类似于传统的在数据行中,您需要为每个属性创建一个联接

毫不奇怪,这会创建一个包含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, ...)

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

对于更清晰的查询,我将使用如下内容:

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 (...)
联接可能会保留,但这取决于数据的结构。

查询中没有联合,只有两个联合

非常好的响应比尔!如果不更改架构,我想不出一个好的解决方案,所以我一直在重新加载这个问题,看看其他人会怎么说。我喜欢你的解决方案。同意。感谢提供信息和解决方案!