【发布时间】:2015-06-03 18:22:12
【问题描述】:
我们当前的设置看起来有点像这样。
public_entry(5.000.000 行)→telephone_number(5.000.000 行)→ user(400.000 行)
3 个表,右侧的箭头表示外键约束,其中包含来自右表的外键(整数)。
现在我们有两个想要在网络应用中呈现的数据的“视图”。
- 根据用户属性显示带有公共条目的电话号码(例如,仅来自男性用户的号码),有点像分数。
- 根据输入日期显示带有公开条目的电话号码
无论号码是否符合您的需求,每个结果都应获得一个分数(例如,您正在寻找水管工,如果该号码在您所在的地区并且相关用户是水管工,则电话号码应该得分高)。
我们尝试了几种方法来解决这个问题,有两种情况。
第一种方法在表上执行带有 INNER JOIN 的 SELECT,如下所示
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 获取电话号码和用户,计算分数并丢弃结果,如果电话号码和用户没有匹配我们的过滤器/兴趣。
通常不会考虑第二种方法,因为它会为单个页面加载创建超过 300 个查询。 Foreach 处理结果并在 foreach 中调用 SELECT 通常被认为是不好的风格。
但是方法二在生产系统上执行。不太好,但不会花费更多 tahn 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 秒的执行时间。
这只是一个示例查询。我可以取出哪里,它的表现会差一点。一般来说,如果我们对数据执行一个带有单个 INNER JOIN 的 SELECT COUNT(),查询会爆炸(30 秒)
【问题讨论】:
-
很难说没有看到您正在运行的实际查询以及解释、表架构信息、所需的查询结果等。我怀疑嵌套查询是否是一个好的解决方案。
-
@MikeBrant 我会尝试添加更多信息
-
一些真正有用的信息是查询的解释计划。通过在其前面加上
DESC来描述查询,例如DESC SELECT ...。可能的罪魁祸首是您的查询缺少覆盖索引。通过该解释计划,我们可以建议可能有帮助的索引。 -
性能很大程度上取决于 (1) WHERE 子句和 (2) 索引。请告诉我们两个。在您的特定情况下,ORDER BY 不能用于优化。
-
@RickJames 我将在接下来的几个小时内添加信息。