【问题标题】:MySQL Matching Columns from Same Table来自同一表的 MySQL 匹配列
【发布时间】:2012-07-22 23:22:52
【问题描述】:

好的,一些入门;我是专家级的 PHP/JS/C 开发人员,但一直无法全面掌握 MySQL。如果你能回答我的问题,那就太好了,但如果你能指出我的资源的方向,以了解复杂的 MySQL 查询的注意事项(主要是从效率的角度来看),那将同样有帮助)。

目标

我需要在单个表中找到相似之处/重叠,同时仍然提取整个结果集(与另一个表中的实际标题/描述内容进行 LEFT JOIN)。

表格极其简单;它包含 3 列(pageusertime)。

基本上每个查询将有两个用户。我需要提取匹配User 1 的所有结果的计数、匹配User 2 的所有结果的计数以及重叠的所有列(加上左连接)(其中User 1User 2 在表中都有匹配项.

示例查询

此查询有效,但速度极慢(到了需要几分钟才能运行的程度),而且我猜测由于子查询而效率低下。如果任何 SQL 专家能指出一种更有效的方法来做到这一点(以及为什么),将不胜感激。

SELECT DISTINCT `page`, 
    (SELECT COUNT(*) FROM `m_likes` WHERE `user` = "1") AS userLikes,
    (SELECT COUNT(*) FROM `m_likes` WHERE `user` = "2") AS friendLikes

    FROM `m_likes` LEFT JOIN `app_pages` AS page ON (page.id = `page`)

        WHERE `page` IN (SELECT `page` FROM `m_likes` WHERE `user` = "1") 
        AND `page` IN (SELECT `page` FROM `m_likes` WHERE `user` = "2")

        AND (`user` = "1" OR `user` = "2")

解释查询结果

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY     m_likes index   NULL    page    604 NULL    35043   Using where; Using index; Using temporary
1   PRIMARY     page    eq_ref  PRIMARY PRIMARY 767 tablename.m_likes.page  1   
5   DEPENDENT SUBQUERY  m_likes unique_subquery page    page    604 func,const      1   Using index; Using where
4   DEPENDENT SUBQUERY  m_likes unique_subquery page    page    604 func,const      1   Using index; Using where
3   SUBQUERY    m_likes index   NULL    page    604 NULL    35043   Using where; Using index
2   SUBQUERY    m_likes index   NULL    page    604 NULL    35043   Using where; Using index

表架构

app_pagesidVARCHAR(255)、nameVARCHAR(255)、categoryVARCHAR(255)

m_likespageVARCHAR(255)、userVARCHAR(255)、timeINT(20)

m_likes.page = app_pages.id

另外值得注意的是,不幸的是,用户和页面 ID 必须是 VARCHAR 而不是 INT,因为不能保证这可以在 64 位系统上运行,并且某些 ID 值大于允许的最大值32 位系统...希望这不会对性能造成重大影响。

输出示例

array (size=156)
  0 => 
    array (size=6)
      'page' => string '100861973286778' (length=15)
      'time' => string '1297383617' (length=10)
      'name' => string 'Leila' (length=5)
      'category' => string 'Book' (length=4)
      'userLikes' => string '104' (length=3)
      'friendLikes' => string '52' (length=2)
  1 => 
    array (size=6)
      'page' => string '10150160788195604' (length=17)
      'time' => string '1272653871' (length=10)
      'name' => string 'Frisbee Golfing' (length=15)
      'category' => string 'Interest' (length=8)
      'userLikes' => string '104' (length=3)
      'friendLikes' => string '52' (length=2)

【问题讨论】:

  • 使用EXPLAIN 更好地了解 MySQL 如何执行您的查询
  • 我已经尝试过使用 EXPLAIN 但坦率地说它并没有那么有用;该查询完全按照我的预期执行,但它并没有让我了解如何更好地设计它,而这正是我希望 SQL 专家能够做到的。
  • 你能把结果贴在这里吗?
  • @Julian,如果您发布表架构(m_likesapp_pages 中的列),我们会更容易解读您的问题
  • 解释有问题的结果; cmets 中的格式问题。添加了表架构。

标签: mysql sql database-design


【解决方案1】:

您的查询运行如此缓慢的原因是您正在执行 FOUR 个单独的子查询,这些子查询实际上最终会为 EACH 行执行。

相反,您可以对子选择进行笛卡尔积以获得 total 计数(仅执行一次):

SELECT a.page, c.userLikes, c.friendLikes
FROM m_likes a
INNER JOIN app_pages b ON a.page = b.id
CROSS JOIN
(
    SELECT
        COUNT(CASE WHEN user = '1' THEN 1 END) AS userLikes,
        COUNT(CASE WHEN user = '2' THEN 1 END) AS friendLikes
    FROM m_likes
    WHERE user IN ('1','2')
) c
WHERE a.user IN ('1','2')
GROUP BY a.page
HAVING COUNT(1) = 2

此查询将检索用户 1 和 2 都喜欢的所有页面,以及他们喜欢的总次数(将在结果集中重复)。

【讨论】:

  • 尝试了这个查询,但它似乎不适用于 HAVING COUNT(1) = 2... 我拿出那部分来测试其余部分,它看起来很好,但它正在选择整个结果集(我猜 HAVING 语句是实际分解子集的部分)。知道那里可能有什么吗? edit 在查看 HAVING 命令后,我似乎只需要找出由 CASE 创建的临时列的别名(似乎不是“1”)
  • @Julian,你能解释一下当你输入HAVING 子句时结果集到底有什么问题吗?它会产生错误吗?这里的HAVING 子句基本上选择了用户12 都喜欢的所有页面。这是假设 page -> user 字段的组合是唯一的(用户不能多次喜欢一个页面)。
  • @Julian 另外,此时,如果您从两个表中发布一些示例数据以及所需的输出,将会非常有帮助。
  • 当我添加 HAVING 子句时,它什么也不返回——一个空响应,但没有 SQL 错误。实际用户 ID 当然不同于 1/2,但我尝试了 COUNT(a) = b 的所有排列,假设用户 ID a/b。
  • 将输出示例添加到原始问题
猜你喜欢
  • 1970-01-01
  • 2022-10-13
  • 1970-01-01
  • 2017-12-28
  • 2015-05-07
  • 1970-01-01
  • 2016-02-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多