使用临时表会终止查询计划

时间:2015-01-09 13:33:31

标签: postgresql temp-tables

您好我有一个带有IN子句的查询。 IN-List可以很大,所以我首先创建一个临时表,但是这会破坏我的查询计划并且需要很长时间。

使用temptable

CREATE TEMPORARY TABLE tempcards (cardid bigint) ON COMMIT DROP;
INSERT INTO tempcards (cardid) VALUES (204313100);


EXPLAIN SELECT 
count(*)
 FROM filecardentity sourcecard
 INNER JOIN lessonentity ON (sourcelesson_lessonid = sourcecard.lesson_lessonid) 
 INNER JOIN assignmentdelivery ON (assignmentdelivery.assignment_id = lessonentity.assignment_id)
 --LEFT JOIN filecardentity targetcard ON (targetcard.original_cardid = sourcecard.cardid AND targetcard.assignment_id = lessonentity.assignment_id) 
 WHERE sourcecard.cardid IN (SELECT cardid FROM tempcards) 

"Aggregate  (cost=2006601.72..2006601.73 rows=1 width=0)"
"  ->  Merge Join  (cost=949476.63..1820711.11 rows=74356243 width=0)"
"        Merge Cond: (sourcecard.lesson_lessonid = lessonentity.sourcelesson_lessonid)"
"        ->  Sort  (cost=673658.21..688573.90 rows=5966274 width=8)"
"              Sort Key: sourcecard.lesson_lessonid"
"              ->  Nested Loop  (cost=36.75..2201.84 rows=5966274 width=8)"
"                    ->  HashAggregate  (cost=36.75..38.75 rows=200 width=8)"
"                          ->  Seq Scan on tempcards  (cost=0.00..31.40 rows=2140 width=8)"
"                    ->  Index Scan using filecardentity_pkey on filecardentity sourcecard  (cost=0.00..10.81 rows=1 width=16)"
"                          Index Cond: (cardid = tempcards.cardid)"
"        ->  Sort  (cost=275803.27..280152.44 rows=1739667 width=8)"
"              Sort Key: lessonentity.sourcelesson_lessonid"
"              ->  Merge Join  (cost=74428.81..95483.48 rows=1739667 width=8)"
"                    Merge Cond: (assignmentdelivery.assignment_id = lessonentity.assignment_id)"
"                    ->  Index Only Scan using fk_fk11c5a601f3011b4_idx on assignmentdelivery  (cost=0.00..1374.42 rows=51344 width=8)"
"                    ->  Sort  (cost=74402.44..75901.33 rows=599555 width=16)"
"                          Sort Key: lessonentity.assignment_id"
"                          ->  Seq Scan on lessonentity  (cost=0.00..16864.55 rows=599555 width=16)"

=> 800ms的

没有临时表

EXPLAIN SELECT 
count(*)
 FROM filecardentity sourcecard
 INNER JOIN lessonentity ON (sourcelesson_lessonid = sourcecard.lesson_lessonid) 
 INNER JOIN assignmentdelivery ON (assignmentdelivery.assignment_id = lessonentity.assignment_id)
 --LEFT JOIN filecardentity targetcard ON (targetcard.original_cardid = sourcecard.cardid AND targetcard.assignment_id = lessonentity.assignment_id) 
 WHERE sourcecard.cardid IN (204313100) 

"Aggregate  (cost=274.15..274.16 rows=1 width=0)"
"  ->  Nested Loop  (cost=0.00..274.12 rows=12 width=0)"
"        ->  Nested Loop  (cost=0.00..263.02 rows=4 width=8)"
"              ->  Index Scan using filecardentity_pkey on filecardentity sourcecard  (cost=0.00..10.87 rows=1 width=8)"
"                    Index Cond: (cardid = 204313100)"
"              ->  Index Scan using fk_fka046075b829910ba_idx on lessonentity  (cost=0.00..251.42 rows=73 width=16)"
"                    Index Cond: (sourcelesson_lessonid = sourcecard.lesson_lessonid)"
"        ->  Index Only Scan using fk_fk11c5a601f3011b4_idx on assignmentdelivery  (cost=0.00..2.77 rows=1 width=8)"
"              Index Cond: (assignment_id = lessonentity.assignment_id)"

=>的55ms

1 个答案:

答案 0 :(得分:1)

使用CTE和EXISTS的示例:

WITH input AS (
    -- the string '1,2,3,4' can be your input from the client
    SELECT unnest(string_to_array('1,2,3,4', ',')::int[]) AS id -- just an example for the input
)
SELECT  * 
FROM    foo 
WHERE EXISTS(
    SELECT  42  -- just something
    FROM    input   -- your cte or temp table if you don't use a cte at all
    WHERE   input.id = foo -- the "join"
);

如果您仍然想要/必须使用临时表,只需删除查询的第一个(WITH)部分并更改EXISTS以使用临时表。

此示例中的输入是逗号分隔的字符串,其中包含整数,不带空格。