繁体   English   中英

当我只需要WHERE子句中的联接(右)表中的一列时,是否需要左外部联接?

[英]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分钟

该性能问题与联接类型无关。

很有可能是“双头”通配符导致了较长的查询时间。 使用索引将无法改善这些问题。 经验法则:

  1. 与LIKE优先使用equal
  2. 与LIKE'%something'相比,优先使用LIKE'something%'
  3. 与LIKE'%something%相比,优先使用LIKE'%something'
  4. 如果您使用LIKE'%something%,请不要期望闪电般的快速响应时间

认真地,您需要重新考虑使用通配符来提高性能。 您可以使用尾随通配符来获得查询的索引支持,并且如果您在列的反面建立索引,则可以获得对前导通配符的索引支持,但是您需要全文索引(和其他查询)才能获得双端通配符(等于)的任何索引支持。


先前:

我使用外部联接,因为我需要将结果包含在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM