目前,我有两个不同的查询返回完全相同的结果,但是更改过滤结果的参数会使它们的行为方式完全不同。
cartography
查询#1: 22行/ ~860毫米;
SELECT eid FROM t_entidades
WHERE eid IN (
SELECT eid
FROM t_entidades
WHERE entidade_t LIKE '%cartography%'
)
OR eid IN (
SELECT entidade as eid
FROM t_entidade_actividade ea
LEFT JOIN t_actividades a ON a.aid = ea.actividade
WHERE a.actividade LIKE '%cartography%'
)
查询#2: 22行/ ~430ms;
SELECT eid FROM t_entidades WHERE entidade_t LIKE '%cartography%'
UNION
SELECT entidade as eid
FROM t_entidade_actividade ea
LEFT JOIN t_actividades a ON a.aid = ea.actividade
WHERE a.actividade LIKE '%cartography%'
cart
查询#1: 715行/ ~870毫米;
查询#2: 715行/ ~450ms
car
查询#1:从不等待足够长的时间......它似乎需要永远,超过1秒会太多
-- EXPLAIN OUTPUT:
"QUERY PLAN"
"Seq Scan on t_entidades (cost=44997.40..219177315.47 rows=500127 width=4)"
" Filter: ((SubPlan 1) OR (hashed SubPlan 2))"
" SubPlan 1"
" -> Materialize (cost=37712.46..38269.55 rows=40009 width=4)"
" -> Seq Scan on t_entidades (cost=0.00..37515.45 rows=40009 width=4)"
" Filter: ((entidade_t)::text ~~ '%car%'::text)"
" SubPlan 2"
" -> Hash Join (cost=36.48..7284.20 rows=298 width=4)"
" Hash Cond: (ea.actividade = a.aid)"
" -> Seq Scan on t_entidade_actividade ea (cost=0.00..5826.63 rows=378163 width=8)"
" -> Hash (cost=36.46..36.46 rows=1 width=4)"
" -> Seq Scan on t_actividades a (cost=0.00..36.46 rows=1 width=4)"
" Filter: ((actividade)::text ~~ '%car%'::text)"
查询#2: 23661行/ ~860毫秒
-- EXPLAIN OUTPUT:
"QUERY PLAN"
"HashAggregate (cost=45303.48..45706.55 rows=40307 width=4)"
" -> Append (cost=0.00..45202.72 rows=40307 width=4)"
" -> Seq Scan on t_entidades (cost=0.00..37515.45 rows=40009 width=4)"
" Filter: ((entidade_t)::text ~~ '%car%'::text)"
" -> Hash Join (cost=36.48..7284.20 rows=298 width=4)"
" Hash Cond: (ea.actividade = a.aid)"
" -> Seq Scan on t_entidade_actividade ea (cost=0.00..5826.63 rows=378163 width=8)"
" -> Hash (cost=36.46..36.46 rows=1 width=4)"
" -> Seq Scan on t_actividades a (cost=0.00..36.46 rows=1 width=4)"
" Filter: ((actividade)::text ~~ '%car%'::text)"
所以,使用查询#1搜索car
似乎需要永远...考虑到SELECT eid FROM t_entidades
只需要大约4秒返回所有350k +行,这很有趣......
不同步骤中查询#1的EXPLAIN
之间的唯一区别是,对于car
,出现以下行:“ - > Materialise(cost = 37712.46..38269.55 rows = 40009 width = 4)“
如果有人愿意解释为什么查询#1需要这么长时间来执行最后一个例子以及解释的每一步到底发生了什么,我将非常感激,因为我似乎永远不会得到它......
答案 0 :(得分:1)
这是我看到的第一个postgresql执行计划,但看起来第一个计划是在t_entidades上进行表扫描,然后对于每一行,它执行下面的所有操作,包括更多的表扫描。
在第二个计划中,它仍然执行两次内部扫描但是已经对结果进行了分析。
假设您的表中有100行,第一个计划执行201个表扫描,第二个计划执行2.表示: - )
答案 1 :(得分:1)
第一个查询太奇怪了,它只会混淆queryplanner。第一个子查询不应该是子查询,第二个子查询的LEFT JOIN应该是INNER JOIN,但也可以在没有子查询的情况下编写。
第二个查询还有一个LEFT JOIN,它实际上是一个INNER JOIN,检查WHERE条件。
SELECT eid FROM t_entidades WHERE entidade_t LIKE '%cartography%'
UNION
SELECT
entidade as eid
FROM
t_entidade_actividade ea
INNER JOIN t_actividades a ON a.aid = ea.actividade
WHERE
a.actividade LIKE '%cartography%'
您是否在aid
和actividade
列上有索引?
答案 2 :(得分:1)
你有连接真的没必要。我来使用经验法则,如果我实际上没有使用字段作为返回集的一部分,我尝试使用EXISTS测试而不是JOINING。类似的东西:
SELECT te.[eid]
FROM [t_entidades] AS te
WHERE te.[entidade_t] LIKE '%cartography%'
OR EXISTS (
SELECT 1
FROM [t_entidade_actividade] AS ea
WHERE ea.[entidade] = te.[eid]
AND EXISTS (
SELECT 1
FROM [t_actividades] AS ta
WHERE ta.[aid] = ea.[actividade]
AND ta.[actividade] LIKE '%cartography%'
)
)
答案 3 :(得分:0)
查询#1的计划读给我:
“解析分析”能够告诉您步骤1.1和1.2实际运行的频率...如果步骤1中的每一行的扫描都在步骤1中,那么您的查询时间将是增长O(n ^ 2)其中n是t_entidades中的行数,每次迭代1.1使用的临时空间将随着该表中匹配数的增加而增加。
你的查询2写的好多了,恕我直言。两组ID中的每一组都以完全不同的方式生成,因此将它们放在单独的查询中并使用UNION在最后将它们合并在一起。它还会在查询1中删除t_entidades的无用外部扫描,它只是从where子句传递ID。 (并不是说它与PostgreSQL有关,但它也清楚地表明两个扫描可以并行运行然后合并,但不要介意。)
t_entidade_actividade.actividade
可能需要索引吗?