LEFT JOIN - 缩小范围

时间:2016-09-02 12:43:02

标签: mysql sql left-join

我目前在使用我刚刚在新工作上继承的旧应用程序时出现问题。我有一个SQL查询,响应时间太长,我需要找到一种方法来固定它。 此查询作用于3个表:

  • SESSION包含所有用户访问
  • CONTACT包含人们通过表单发送的所有邮件,其中包含" session_id"链接回SESSION id字段的字段
  • 帐户包含用户帐户(在网站上注册的用户)及其用户ID#34;字段在SESSION中链接回来(通过" SESSION.account_id"字段)。除了SESSION表(遗留应用程序......)之外,ACCOUNT和CONTACT没有任何关联。

不幸的是,我无法改变这种结构。

我的查询尝试恢复所有有趣的会话以便向管理员提供服务。我需要查找链接回帐户或联系表单的所有会话。

目前,查询结构如下:

SELECT s.id
/*  a few fields from ACCOUNT and CONTACT tables */

FROM session s
LEFT JOIN account act ON act.id = s.account_id
LEFT JOIN contact c on c.session_id = s.id
WHERE s.programme_id = :program_id
AND (
c.id IS NOT NULL
OR
act.id IS NOT NULL
)

问题是,SESSION表的增长速度非常快(正如您所期望的那样),并且对于某些程序(即查询中的programme_id),它会减慢400k记录的速度。

我尝试使用带有两个INNER JOIN查询的UNION查询,一个在SESSION和ACCOUNT之间,另一个在SESSION和CONTACT之间,但它没有给我相同数量的记录,我没有'我真的明白为什么。

有人可以帮我找到更好的方法来进行此查询吗?

提前多多感谢。

2 个答案:

答案 0 :(得分:2)

我认为你只需要索引。对于此查询:

SELECT s.id
/*  a few fields from ACCOUNT and CONTACT tables */

FROM session s LEFT JOIN
     account act
     ON act.id = s.account_id LEFT JOIN
     contact c 
     ON c.session_id = s.id
WHERE s.programme_id = :program_id AND
      (c.id IS NOT NULL OR act.id IS NOT NULL);

您需要session(programme_id, account_id, id)account(id)contact(session_id)上的索引。

programme_id作为session索引中的第一列非常重要。

答案 1 :(得分:0)

@Gordon已经建议你添加索引,这通常是简单有效的解决方案,所以我将回答你问题的另一部分。

  

我尝试使用带有两个INNER JOIN查询的UNION查询,一个介于两者之间   SESSION和ACCOUNT以及SESSION和CONTACT之间的另一个,但是   它没有给我相同数量的记录,我也没有   理解为什么。

该部分相当简单:JOIN返回一个结果集,其中包含连接在一起的两个表的行。因此,在第一种情况下,您最终会得到一个看起来像

的结果
session.id, session.column2, session.column3, ..., account.id, account.column2, account.column3, ....

和第二个

session.id, session.column2, session.column3, ..., contact.id, contact.column2, contact.column3, ....

然后,除非UNIONcontact表与correspoding类型具有相同数量的列,否则account将失效,这是不太可能的。否则,数据库将无法执行UNIONFrom the docs(强调我的):

  

第一个SELECT语句中的列名用作返回结果的列名。 每个SELECT语句的相应位置中列出的选定列应具有相同的数据类型。(例如,第一个语句选择的第一列应与其他语句选择的第一列具有相同的类型。)

如果您不确定,只需单独执行两个INNER JOIN并比较结果。

如果您想坚持使用UNION解决方案,请确保仅在相应的列上执行SELECT:执行SELECT s.id会很简单,但它应该可以正常工作。 / p>