![](/img/trans.png)
[英]Combining LEFT OUTER JOIN and WHERE clause on right table in Doctrine2
[英]Is a left outer join needed when I only need one column from the joined (right) table in the WHERE clause?
我有以下左外部联接查询:
SELECT table_left.pk_id, table_left.name
FROM table_left left outer join table_right on table_right.fk_id = table_left.pk_id
WHERE table_right.name like '%entered search value%'
我的问题是table_right有超过1,000,000行和超过60列。 该查询大约需要1分钟,我认为这是因为它正在对所有列进行完全外部联接。 我不需要所有的列。 我只需要使用一列(table_right.fk_id),以便可以在WHERE子句中连接两个表和另一列(table_right.name)。
我使用外部联接,因为我需要将结果包含在table_left中,而table_right中没有行。
任何有助于提高上述查询速度的建议将不胜感激。
这是我拥有的两个表的示例:
+-------------------+
| table_left |
+-------------------+
| pk_id | name |
+-------+-----------+
| 1 | IBM |
+-------+-----------+
| 2 | Facebook |
+-------+-----------+
| 3 | Google |
+-------+-----------+
| 4 | Microsoft |
+-------+-----------+
+--------------------------------------------+
| table_right |
+--------------------------------------------+
| table_right_pk_id | fk_id | job_details |
+-------------------+-------+----------------+
| 1 | 1 | Tester |
+-------------------+-------+----------------+
| 2 | 2 | Toilet Cleaner |
+-------------------+-------+----------------+
| 3 | 2 | Secretary |
+-------------------+-------+----------------+
| 4 | 3 | Developer |
+-------------------+-------+----------------+
我希望能够搜索“名称”(在table_left中)和“ job_details”(在table_right中),但使用table_left列。 这是我提出的查询,在查询下有一些预期结果:
SELECT table_left.pk_id, table_left.name
FROM table_left left outer join table_right on table_right.fk_id = table_left.pk_id
WHERE table_right.name LIKE '%searchTerm%' OR table_left.name LIKE '%searchTerm%'
例1
searchTerm ='IBM'
结果:
+-------------------+
| result |
+-------------------+
| pk_id | name |
+-------+-----------+
| 1 | IBM |
+-------+-----------+
例子2
searchTerm ='测试人员'
结果:
+-------------------+
| result |
+-------------------+
| pk_id | name |
+-------+-----------+
| 1 | IBM |
+-------+-----------+
实施例3
searchTerm ='微软'
结果:(即使table_right中没有记录,仍应返回Microsoft)
+-------------------+
| result |
+-------------------+
| pk_id | name |
+-------+-----------+
| 4 | Microsoft |
+-------+-----------+
实施例4
searchTerm ='开发人员'
结果:
+-------------------+
| result |
+-------------------+
| pk_id | name |
+-------+-----------+
| 2 | Facebook |
+-------+-----------+
如果您需要在table_left中返回所有结果(无论是否匹配),那么就像您正在做的那样,左联接是正确的,因此不必担心尝试切换它。
该查询大约需要1分钟,我认为这是因为它正在对所有列进行完全外部联接。 我不需要所有的列。
让我们清楚:加入, 只对您在连接条件中列出的列操作:在这种情况下,table_right.fk_id和table_left.pk_id。 但是,您非常正确,非常大的表将需要更长的时间来处理。 如果不需要其余的列,则最好在进行任何连接之前将其排除在外,因为输出表的宽度较小(这意味着返回该输出表时速度会提高)。
当试图提高联接性能时,MySQL的经验法则是使用索引。 用外行的话来说,索引基本上告诉数据库使用特定的一个或多个列作为对表的查找。 添加索引后,我对速度的提高感到震惊。
左联接很好:
SELECT table_left.pk_id, table_left.name
FROM table_left
LEFT JOIN table_right on table_right.fk_id = table_left.pk_id
WHERE table_right.name LIKE '%searchTerm%' OR table_left.name LIKE '%searchTerm%'
查询大约需要1分钟
该性能问题与联接类型无关。
很有可能是“双头”通配符导致了较长的查询时间。 使用索引将无法改善这些问题。 经验法则:
认真地,您需要重新考虑使用通配符来提高性能。 您可以使用尾随通配符来获得查询的索引支持,并且如果您在列的反面建立索引,则可以获得对前导通配符的索引支持,但是您需要全文索引(和其他查询)才能获得双端通配符(等于)的任何索引支持。
先前:
我使用外部联接,因为我需要将结果包含在table_left中,而table_right中没有行。
如果仅按WHERE table_right.name like '%entered search value%'
进行过滤,这根本就没有意义WHERE table_right.name like '%entered search value%'
从table_right到table_left匹配的行只能从该where子句返回。
我认为您正在夸大您的解释以及您试图获得的结果。 如果我在解释您的问题时是正确的,则您需要加入。 您需要从LEFT表的REGARDLESS中获得权利,但是如果该权利恰好可以使您的任期合格,那么请根据需要获取条目。
您的查询是将条件应用于相同的左表字段,而不是左右。
为了在连接到具有60(或更多)列的RIGHT边表时帮助优化查询,但是您仅在FK_ID及其“ Job_Details”(根据您的Tester和Developer查询示例)上进行比较,我将构建一个复合索引仅在这两列上,因此可以针对(FK_ID,Job_Details)上的连接和搜索进行优化。 这样,引擎可以直接从INDEX获取答案,而不必返回到所有60列都存在的原始数据页面。 Table_Left还应在(PK_ID,Name)上具有一个复合索引以对其进行优化。
现在,基于'%someValue%'的搜索,您将需要进行全文搜索,因为前导'%'意味着您不知道字符串前有多少个字符,字符串后也没有多少个,只要搜索字符串在查询中位于“ SOMEWHERE”。 除非您需要,否则我建议不要使用前导'%',但这是您的要求。
select
LT.PKID,
LT.Name
from
Table_Left LT
LEFT JOIN Table_Right RT
on LT.PK_ID = RT.FK_ID
AND RT.JOB_Details LIKE 'Tester%'
where
LT.Name Like 'Tester%'
OR NOT RT.FK_ID IS NULL
因此,这将基于名称为“ Tester”的左表或相应的作业详细信息为“ Tester”的右表为您提供。 但我认为这不是最佳选择。
但是,我实际上建议在(Job_Details,FK_ID)上提供不同的索引,然后使用DISTINCT进行UNION查询。
select DISTINCT
LT.PKID,
LT.Name
from
Table_Left LT
where
LT.Name Like 'Tester%'
UNION
select
LT.PKID,
LT.Name
FROM
Table_Right RT
JOIN Table_Left LT
on RT.FK_ID = LT.PK_ID
where
RT.JOB_Details LIKE 'Tester%'
这样,通过按名称查找时,左表针对其独特性进行了优化,通过搜索其JobDetails并获取相应的左表Name信息来对右表进行了优化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.