【问题标题】:Optimization Needed For Dual Left Join Query双左连接查询需要优化
【发布时间】:2016-02-16 01:21:59
【问题描述】:

我一直在为 mysql 连接而苦苦挣扎,但已经开始合并更多,但尽管阅读了数十篇教程和 mysql 手册,但仍难以理解。

我的情况是我有 3 张桌子:

/* 基本上是一个保存粉丝记录的表 */

创建表`粉丝`( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `first_name` varchar(255) 默认为空, `middle_name` varchar(255) 默认为空, `last_name` varchar(255) 默认为 NULL, `email` varchar(255) 默认为空, `join_date` 日期时间 DEFAULT NULL, `twitter` varchar(255) 默认为空, `twitterCrawled` 日期时间默认为 NULL, `twitterImage` varchar(255) 默认为空, 主键(`id`), 唯一键 `email` (`email`) ) 引擎=MyISAM AUTO_INCREMENT=20413 默认字符集=latin1; /* 我们的推特粉丝列表 */ 创建表`twitterFollowers`( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `screenName` varchar(25) 默认为空, `twitterId` varchar(25) 默认为空, `customerId` int(11) 默认为空, `uniqueStr` varchar(50) 默认为空, 主键(`id`), 唯一键 `unique` (`uniqueStr`) ) 引擎=InnoDB AUTO_INCREMENT=13426 默认字符集=utf8; /* 根据粉丝与我们的追随者的电子邮件/屏幕名称比较,建议推特追随者可能匹配的表格 如果有人(即版主)确认或否认这是一场不错的比赛,他们会在 `dismissed` 中添加一个日期戳 */ 创建表`contentSuggestion`( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `userId` int(11) 默认为空, `fanId` int(11) 默认为空, `twitterAccountId` int(11) 默认为空, `contentType` varchar(50) 默认为空, `contentString` varchar(255) 默认为空, `添加`日期时间默认为空, `dismissed` 日期时间 DEFAULT NULL, `uniqueStr` varchar(255) 默认为 NULL, 主键(`id`), 唯一键 `unstr` (`uniqueStr`) ) 引擎=InnoDB AUTO_INCREMENT=2 默认字符集=utf8;

我想要得到的是:

SELECT [粉丝专栏] WHERE 粉丝网名在 twitterfollowers 中 并且在 contentSuggestion 中没有粉丝屏幕名称(带有已关闭的日期戳)

My attempts so far:

~33 秒

从粉丝中选择fans.id,tf.screenName 作为col1,tf.twitterId 作为col2 左加入 twitterFollowers tf ON tf.screenName = fan.emailUsername LEFT JOIN contentSuggestion cs ON cs.contentString = tf.screenName WHERE dismissed IS NULL GROUP BY(fans.id) HAVING col1 != ''

~14 秒

SELECT id, emailUsername FROM Fans WHERE emailUsername IN(SELECT DISTINCT(screenName) FROM twitterFollowers) AND emailUsername NOT IN(SELECT DISTINCT(contentString) FROM contentSuggestion WHERE dismissed IS NULL) GROUP BY (fans.id);

9.53 秒

从粉丝中选择fans.id,tf.screenName 作为col1,tf.twitterId 作为col2 LEFT JOIN twitterFollowers tf ON tf.screenName = fan.emailUsername WHERE tf.uniqueStr NOT IN(SELECT uniqueStr FROM contentSuggestion WHERE dismissed IS NULL)

我希望有更好的方法。我一直在努力在单个 LEFT JOIN 之外真正使用 JOINS,这已经帮助我大大加快了其他查询的速度。

感谢您能给我的任何帮助。

【问题讨论】:

    标签: php mysql join


    【解决方案1】:

    我会选择第二种方法的变体。代替IN,使用EXISTS。然后添加正确的索引并移除聚合:

    SELECT f.id, f.emailUsername
    FROM fans f
    WHERE EXISTS (SELECT 1
                  FROM twitterFollowers tf
                  WHERE f.emailUsername = tf.screenName
                 ) AND
          NOT EXISTS (SELECT 1
                      FROM contentSuggestion cs
                      WHERE f.emailUsername = cs.contentString AND
                            cs.dismissed IS NULL
                     ) ;
    

    然后确保您具有以下索引:twitterFollowers(screenName)contentSuggestion(contentString, dismissed)

    一些注意事项:

    • 使用IN时,不要使用SELECT DISTINCT。我不能 100% 确定 MySQL 总是足够聪明,可以忽略子查询中的 DISTINCT(这是多余的)。
    • 历史上,EXISTS 在 MySQL 中比 IN 快。优化器在最近的版本中得到了改进。
    • 为了提高性能,您需要正确的索引。 然后确保您具有以下索引:twitterFollowers(screenName)contentSuggestion(contentString, dismissed)
    • 假设fan.id 是唯一的(一个非常合理的假设),您不需要最终的group by

    【讨论】:

      猜你喜欢
      • 2017-04-04
      • 2019-03-08
      • 2011-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-03
      • 2020-02-14
      • 1970-01-01
      相关资源
      最近更新 更多