使用JOIN的多个SELECT与单个查询

时间:2015-03-30 16:19:25

标签: php mysql join

我们目前的设置看起来有点像这样。

public_entry(5.000.000行)→telephone_number(5.000.000行)→user(400.000行)

3个表,右边的箭头表示包含右表中的外键(整数)的外键约束。

现在我们有两个"观点"我们希望在我们的网络应用程序中显示的数据。

  1. 根据用户属性显示包含公共条目的电话号码(例如,只有男性用户的号码),有点像分数。
  2. 根据录入日期显示具有公开条目的电话号码
  3. 每个结果应该得到一个分数,分数是否符合您的需求(例如,您寻找水管工,如果数字在您所在区域,相关用户是水管工,电话号码应该得分高)。

    我们尝试了两种方案来解决这个问题。

    第一种方法在表上执行SELECT with INNER JOIN,如下所示

    SELECT ..., (...) as score
        FROM public_entry pe
        INNER JOIN telephone_numer tn ON tn.id = pe.numberid
        INNER JOIN user u ON u.id = tn.userid WHERE ... ORDER BY score
    

    在较小的系统上使用此查询,即使在负载下,生产系统的1/4也能很好地执行。 然而,当我们将这个查询放入生产系统时,它会破坏执行时间超过30秒。

    第二种方法是在public_entry上使用单个SELECT过滤所有public_entries而不使用任何JOIN并迭代它们为每个public_entry调用一个SELECT来获取telephone_number和用户,计算得分并丢弃结果如果telephone_number和user不匹配我们的过滤器/兴趣。

    通常从不考虑第二种方法,因为它为单个页面加载创建了300多个查询。 Foreach结果并在foreach中调用SELECT通常被认为是不好的风格。

    然而,第二种方法在生产系统上执行。不好,但不会超过1-3秒,但在测试系统上也表现不佳。

    您对问题的位置有什么建议吗?

    修改

    查询

    SELECT COUNT(p.id)
        FROM public_entry p, fon f, user u
        WHERE p.isweb = 1
          AND f.hidden = 0
          AND f.deleted = 0
          AND f.id = p.fonid
          AND u.id = f.userid
          AND u.gender = "female"
    

    此查询的执行时间为3秒。

    enter image description here

    这只是一个示例查询。我可以拿出去哪里,它的表现稍差一点。一般情况下,如果我们对数据进行单个INNER JOIN的SELECT COUNT(),则查询会爆炸(30秒)

1 个答案:

答案 0 :(得分:0)

我没有你想要的神奇答案,但这里有一些表现不佳的'原因',以及一些可能的解决方法(有警告)。

iswebhiddendeletedgender中哪一个最“有选择性”?这个优化器认为它们没用,而且很烦人。也就是说,如果每个都有两个值,那么该字段上的INDEX可能是无用的。因此,它选择一个表,进行完整扫描,然后进入下一个表等。请注意,在EXPLAIN中,它首先选择了最小的表(user)。这通常是当WHERE子句看起来没有用时优化器所执行的操作。

MySQL是否能完成所有这些工作,或者你所做的一切工作都是同样的努力。也许你可以更快地完成它,因为你可以在内存中有一个简单的关联数组,而MySQL被编码为允许表存放在磁盘上,逐块“缓存”在RAM中。但是,如果你没有足够的内存来加载所有东西,你就会陷入MySQL。

如果您实际删除了“隐藏”和“已删除”行,则任务会更快一些。

你的两个选择看起来不太相似。你是否建议有各种各样的SELECT?你有效地需要查看所有3个表中的大部分来获得“得分”或“计数”吗?

让我们从数据仓库方法看一下......有些数据是“静态的”;也就是说,不变,可以归纳?如果是这样,将小计(COUNT(*))预先计算到摘要表中将使最终查询更快。 DW通常涉及白天的小计。但它要求这些小计不会改变。

COUNT(x)有检查xNULL的开销。通常这不是必需的,COUNT(*)可以为您提供所需的内容。

您多久运行一次相同的SELECT?或者,至少,类似的SELECT?你需要最高分吗?我正在钓鱼,在半夜运行所有可能的查询,然后使用24小时的结果。请注意,通过一次执行多项操作,某些查询可以更快地运行。例如,代替“女性”与“男性”的两个SELECT,执行一个SELECT和GROUP BY gender

相关问题