首先我们要知道,出现这个问题,是由于使用了Merge Join 。但是,参与的其中一个表的数据并没有按期望顺序排序,违反了 Merge Join 的前提条件(即两个输入都按某个键有序)。
举个例子
sql
SELECT COUNT(a.id)
FROM table_a a
JOIN table_b b
ON a.key1 = b.key1
AND a.key2 = b.key2
AND b.filter_col = 123456
WHERE
a.status = 0
AND a.score > 50000
AND a.lgth >= 3
AND a.ptop >= 10000
AND a.vendor_id != 29;
由于此时已经无法使用EXPLAIN (ANALYZE, BUFFERS) 去分析执行计划,不能判断是a表还是b表、或者两个表都是无序的。所以,将查询拆分,分别去分析执行计划。
1.如果没有相关索引,创建索引即可
2.如果有索引,但是没有使用,考虑是否可选择性不够。
例如filter_col = 123456数据超过总表的30%,此时就不会再走索引。需要想其他办法。
如果filter_col = 123456没有超过总表的30%,那么考虑是否是死元组过多,清理死元组
今天遇到的问题是b表的死元组过多,加上filter_col = 123456条件占了20%,实际上也是很多了,所以导致查询计划生成器没有使用索引,以至于出现mergejoin的错误。
除此以外,还有别的奇技淫巧
1.关闭mergejoin
sql
SET enable_mergejoin = off;
2.改写查询,使用exists,不过性能可能会很差