称如下这种查询为关联子查询:
SELECT ... FROM t1 WHERE t1.a IN (SELECT b FROM t2);
MySQL5.5 的 关联子查询有很严重的性能问题,《高性能 MySQL》(第三版) 6.5.1 节里有提到,
MySQL 自己的 subquery-restrictions 文档 的第一条也提到了这点。
我们自己部署的 gitlab 用了 MySQL5.5 作为数据库(gitlab 官方推荐使用 PG...), 代码里面有很多关联子查询,比如下面链接里的代码: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/finders/union_finder.rb#L6
class UnionFinder
def find_union(segments, klass)
if segments.length > 1
union = Gitlab::SQL::Union.new(segments.map { |s| s.select(:id) })
klass.where("#{klass.table_name}.id IN (#{union.to_sql})") # 这里会成 IN() 子查询
else
segments.first
end
end
end
目前解决的方法是用 union 先把 id 查出来然后再给 where:
ids = klass.find_by_sql(union.to_sql).map(&:id)
klass.where("#{klass.table_name}.id" => ids)
两个问题:
虽然 MySQL 5.7 的 subquery-restrictions 文档里已经把 5.5 文档里第一条关于关联子查询的内容移除了,但是在 5.7 上测试以后发现还是很慢!是我的使用姿势不对么