Обсуждение: Expensive where clause
Hi All,
I have been working on a SQL statement that contains a WHERE clause of the
form WHERE column1 > column2. The query runs pretty quickly (285ms) without
the WHERE clause but slows to a relative crawl (5850ms) when it is included.
Anu suggestions on how to improve the performance would be greatly appreciated.
Kind Regards,
Keith
SELECT all_shipped_items.item_id,
sum (all_shipped_items.quantity) AS quantity
--Get the inventory items and the last date they were counted.
FROM (
SELECT items.id AS item_id,
COALESCE(last_inventory.inventory_date, CAST('0001-01-01' AS
date)) AS inventory_date
FROM peachtree.tbl_item AS items
LEFT OUTER JOIN ( SELECT DISTINCT ON ( inventory.tbl_data.item_id)
inventory.tbl_data.item_id,
inventory.tbl_detail.inventory_date
FROM inventory.tbl_data
INNER JOIN inventory.tbl_detail
ON ( inventory.tbl_data.inventory_id =
inventory.tbl_detail.inventory_id )
ORDER BY inventory.tbl_data.item_id,
inventory.tbl_data.inventory_id DESC
) AS last_inventory
ON ( items.id = last_inventory.item_id )
WHERE ( NOT items.inactive )
AND items.item_class = 1 -- stock item
AND items.item_type IN ( 'DIR', 'NET' )
) AS all_items
--Get the inventory items and the date they were shipped from the invoices.
RIGHT OUTER JOIN (
-- Get the direct items from tbl_line_item.
SELECT invoice.tbl_line_item.quantity,
invoice.tbl_line_item.item_id,
invoice.tbl_detail.ship_date
FROM invoice.tbl_line_item
JOIN peachtree.tbl_item
ON ( invoice.tbl_line_item.item_id = peachtree.tbl_item.id )
JOIN invoice.tbl_detail
ON ( invoice.tbl_line_item.i_number =
invoice.tbl_detail.i_number )
WHERE ( NOT peachtree.tbl_item.inactive )
AND peachtree.tbl_item.item_class = 1 -- stock item
AND peachtree.tbl_item.item_type = 'DIR'
UNION ALL
-- Get the assembly items from tbl_line_item.
SELECT invoice.tbl_line_item.quantity *
peachtree.tbl_assembly.quantity
AS quantity,
peachtree.tbl_assembly.component_id AS item_id,
invoice.tbl_detail.ship_date
FROM invoice.tbl_line_item
JOIN peachtree.tbl_assembly
ON ( invoice.tbl_line_item.item_id =
peachtree.tbl_assembly.id )
JOIN peachtree.tbl_item
ON ( invoice.tbl_line_item.item_id = peachtree.tbl_item.id )
JOIN invoice.tbl_detail
ON ( invoice.tbl_line_item.i_number =
invoice.tbl_detail.i_number )
WHERE ( NOT peachtree.tbl_item.inactive )
AND peachtree.tbl_item.item_type = 'ASY'
UNION ALL
-- Get the direct items from tbl_item_bom.
SELECT merged_invoice.quantity *
sales_order.tbl_item_bom.quantity
AS quantity,
sales_order.tbl_item_bom.item_id,
merged_invoice.ship_date
FROM sales_order.tbl_item_bom
JOIN ( SELECT invoice.tbl_detail.i_number,
invoice.tbl_detail.so_number,
invoice.tbl_detail.ship_date,
invoice.tbl_line_item.i_line,
invoice.tbl_line_item.quantity,
invoice.tbl_line_item.item_id
FROM invoice.tbl_detail
JOIN invoice.tbl_line_item
ON ( invoice.tbl_detail.i_number =
invoice.tbl_line_item.i_number )
) AS merged_invoice
ON ( sales_order.tbl_item_bom.number =
merged_invoice.so_number AND
sales_order.tbl_item_bom.line =
merged_invoice.i_line )
JOIN peachtree.tbl_item
ON ( sales_order.tbl_item_bom.item_id = peachtree.tbl_item.id )
WHERE ( NOT peachtree.tbl_item.inactive )
AND peachtree.tbl_item.item_class = 1 -- stock item
AND peachtree.tbl_item.item_type IN ( 'DIR', 'NET' )
UNION ALL
-- Get the assembly items from tbl_item_bom.
SELECT merged_invoice.quantity *
sales_order.tbl_item_bom.quantity *
peachtree.tbl_assembly.quantity
AS quantity,
peachtree.tbl_assembly.component_id AS item_id,
merged_invoice.ship_date
FROM sales_order.tbl_item_bom
JOIN ( SELECT invoice.tbl_detail.i_number,
invoice.tbl_detail.so_number,
invoice.tbl_detail.ship_date,
invoice.tbl_line_item.i_line,
invoice.tbl_line_item.quantity,
invoice.tbl_line_item.item_id
FROM invoice.tbl_detail
JOIN invoice.tbl_line_item
ON ( invoice.tbl_detail.i_number =
invoice.tbl_line_item.i_number )
) AS merged_invoice
ON ( sales_order.tbl_item_bom.number =
merged_invoice.so_number AND
sales_order.tbl_item_bom.line =
merged_invoice.i_line )
JOIN peachtree.tbl_assembly
ON ( sales_order.tbl_item_bom.item_id =
peachtree.tbl_assembly.id )
JOIN peachtree.tbl_item
ON ( sales_order.tbl_item_bom.item_id = peachtree.tbl_item.id )
WHERE ( NOT peachtree.tbl_item.inactive )
AND peachtree.tbl_item.item_type = 'ASY'
) AS all_shipped_items
ON ( all_items.item_id = all_shipped_items.item_id )
WHERE all_shipped_items.ship_date > all_items.inventory_date
GROUP BY all_shipped_items.item_id
On Fri, 18 Feb 2005, Keith Worthington wrote: > I have been working on a SQL statement that contains a WHERE clause of the > form WHERE column1 > column2. The query runs pretty quickly (285ms) without > the WHERE clause but slows to a relative crawl (5850ms) when it is included. > Anu suggestions on how to improve the performance would be greatly appreciated. Explain analyze output for the query with and without the clause would probably be useful for analysis.
On Fri, 18 Feb 2005 21:55:29 -0800 (PST), Stephan Szabo wrote
> On Fri, 18 Feb 2005, Keith Worthington wrote:
>
> > I have been working on a SQL statement that contains a WHERE
> > clause of the form WHERE column1 > column2. The query runs
> > pretty quickly (285ms) without the WHERE clause but slows to
> > a relative crawl (5850ms) when it is included.
> > Any suggestions on how to improve the performance would be
> > greatly appreciated.
>
> Explain analyze output for the query with and without the clause
> would probably be useful for analysis.
Here is the explain analyze output with the WHERE
clause commented out. This one actually ran slow. Usually it is only a few
hundred ms without the WHERE clause.
The larger picture is that I have several of these queries running as
subqueries of a larger statement. The whole statement takes upwords of 5
minutes to run on a single user machine that has minimal data. If I can't
find a way to improve this query I am going to have to go back the the drawing
board and figure out a different way of tackling the problem so that
performance is acceptable.
Thanks in advance for your help.
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=646.35..646.55 rows=80 width=36) (actual
time=1291.409..1291.633 rows=162 loops=1)
-> Hash Left Join (cost=142.94..645.95 rows=80 width=36) (actual
time=1253.595..1288.857 rows=884 loops=1)
Hash Cond: (("outer".item_id)::text = ("inner".item_id)::text)
-> Subquery Scan all_shipped_items (cost=42.06..544.66 rows=80
width=36) (actual time=3.579..34.674 rows=884 loops=1)
-> Append (cost=42.06..543.86 rows=80 width=40) (actual
time=3.574..33.078 rows=884 loops=1)
-> Subquery Scan "*SELECT* 1" (cost=42.06..80.49 rows=1
width=32) (actual time=3.572..13.620 rows=376 loops=1)
-> Nested Loop (cost=42.06..80.48 rows=1
width=32) (actual time=3.568..12.854 rows=376 loops=1)
-> Hash Join (cost=42.06..74.62 rows=1
width=32) (actual time=3.529..8.179 rows=376 loops=1)
Hash Cond: (("outer".item_id)::text =
("inner".id)::text)
-> Seq Scan on tbl_line_item
(cost=0.00..27.37 rows=1037 width=32) (actual time=0.014..1.486 rows=1087 loops=1)
-> Hash (cost=42.06..42.06 rows=1
width=24) (actual time=3.453..3.453 rows=0 loops=1)
-> Index Scan using
idx_tbl_item_item_type on tbl_item (cost=0.00..42.06 rows=1 width=24) (actual
time=0.035..2.789 rows=502 loops=1)
Index Cond:
((item_type)::text = 'DIR'::text)
Filter: ((NOT inactive) AND
(item_class = 1))
-> Index Scan using tbl_detail_pkey on
tbl_detail (cost=0.00..5.84 rows=1 width=8) (actual time=0.005..0.007 rows=1
loops=376)
Index Cond: ("outer".i_number =
tbl_detail.i_number)
-> Subquery Scan "*SELECT* 2" (cost=89.47..199.26
rows=56 width=36) (actual time=6.516..10.144 rows=460 loops=1)
-> Hash Join (cost=89.47..198.70 rows=56
width=36) (actual time=6.511..9.267 rows=460 loops=1)
Hash Cond: (("outer".id)::text =
("inner".item_id)::text)
-> Seq Scan on tbl_assembly
(cost=0.00..87.30 rows=4230 width=52) (actual time=0.809..1.470 rows=587 loops=1)
-> Hash (cost=89.46..89.46 rows=3 width=56)
(actual time=5.637..5.637 rows=0 loops=1)
-> Hash Join (cost=74.64..89.46
rows=3 width=56) (actual time=4.540..5.448 rows=137 loops=1)
Hash Cond: ("outer".i_number =
"inner".i_number)
-> Seq Scan on tbl_detail
(cost=0.00..13.53 rows=253 width=8) (actual time=0.003..0.341 rows=281 loops=1)
-> Hash (cost=74.63..74.63
rows=3 width=56) (actual time=4.483..4.483 rows=0 loops=1)
-> Hash Join
(cost=42.04..74.63 rows=3 width=56) (actual time=1.540..4.278 rows=137 loops=1)
Hash Cond:
(("outer".item_id)::text = ("inner".id)::text)
-> Seq Scan on
tbl_line_item (cost=0.00..27.37 rows=1037 width=32) (actual time=0.004..1.334
rows=1087 loops=1)
-> Hash
(cost=42.03..42.03 rows=5 width=24) (actual time=1.333..1.333 rows=0 loops=1)
-> Index Scan
using idx_tbl_item_item_type on tbl_item (cost=0.00..42.03 rows=5 width=24)
(actual time=0.035..1.078 rows=205 loops=1)
Index
Cond: ((item_type)::text = 'ASY'::text)
Filter:
(NOT inactive)
-> Subquery Scan "*SELECT* 3" (cost=89.66..116.32
rows=1 width=36) (actual time=5.076..6.629 rows=48 loops=1)
-> Nested Loop (cost=89.66..116.31 rows=1
width=36) (actual time=5.071..6.534 rows=48 loops=1)
-> Hash Join (cost=89.66..104.47 rows=2
width=38) (actual time=5.013..5.695 rows=48 loops=1)
Hash Cond: ("outer".so_number =
"inner".number)
-> Seq Scan on tbl_detail
(cost=0.00..13.53 rows=253 width=12) (actual time=0.011..0.341 rows=281 loops=1)
-> Hash (cost=89.66..89.66 rows=1
width=34) (actual time=4.964..4.964 rows=0 loops=1)
-> Hash Join (cost=84.17..89.66
rows=1 width=34) (actual time=4.395..4.882 rows=60 loops=1)
Hash Cond:
(("outer".item_id)::text = ("inner".id)::text)
-> Seq Scan on
tbl_item_bom (cost=0.00..4.32 rows=232 width=34) (actual time=0.014..0.097
rows=61 loops=1)
-> Hash
(cost=84.16..84.16 rows=1 width=24) (actual time=4.351..4.351 rows=0 loops=1)
-> Index Scan using
idx_tbl_item_item_type, idx_tbl_item_item_type on tbl_item (cost=0.00..84.16
rows=1 width=24) (actual time=0.035..3.586 rows=566 loops=1)
Index Cond:
(((item_type)::text = 'DIR'::text) OR ((item_type)::text = 'NET'::text))
Filter: ((NOT
inactive) AND (item_class = 1))
-> Index Scan using tbl_line_item_pkey on
tbl_line_item (cost=0.00..5.90 rows=1 width=10) (actual time=0.008..0.010
rows=1 loops=48)
Index Cond: (("outer".i_number =
tbl_line_item.i_number) AND ("outer".line = tbl_line_item.i_line))
-> Subquery Scan "*SELECT* 4" (cost=47.54..147.80
rows=22 width=40) (actual time=1.594..1.594 rows=0 loops=1)
-> Nested Loop (cost=47.54..147.58 rows=22
width=40) (actual time=1.591..1.591 rows=0 loops=1)
-> Nested Loop (cost=47.54..74.18 rows=1
width=60) (actual time=1.589..1.589 rows=0 loops=1)
-> Hash Join (cost=47.54..62.35
rows=2 width=62) (actual time=1.587..1.587 rows=0 loops=1)
Hash Cond: ("outer".so_number =
"inner".number)
-> Seq Scan on tbl_detail
(cost=0.00..13.53 rows=253 width=12) (never executed)
-> Hash (cost=47.53..47.53
rows=1 width=58) (actual time=1.565..1.565 rows=0 loops=1)
-> Hash Join
(cost=42.04..47.53 rows=1 width=58) (actual time=1.563..1.563 rows=0 loops=1)
Hash Cond:
(("outer".item_id)::text = ("inner".id)::text)
-> Seq Scan on
tbl_item_bom (cost=0.00..4.32 rows=232 width=34) (actual time=0.004..0.071
rows=61 loops=1)
-> Hash
(cost=42.03..42.03 rows=5 width=24) (actual time=1.408..1.408 rows=0 loops=1)
-> Index Scan
using idx_tbl_item_item_type on tbl_item (cost=0.00..42.03 rows=5 width=24)
(actual time=0.022..1.135 rows=205 loops=1)
Index
Cond: ((item_type)::text = 'ASY'::text)
Filter:
(NOT inactive)
-> Index Scan using tbl_line_item_pkey
on tbl_line_item (cost=0.00..5.90 rows=1 width=10) (never executed)
Index Cond: (("outer".i_number =
tbl_line_item.i_number) AND ("outer".line = tbl_line_item.i_line))
-> Index Scan using tbl_assembly_pkey on
tbl_assembly (cost=0.00..73.01 rows=22 width=52) (never executed)
Index Cond: (("outer".id)::text =
(tbl_assembly.id)::text)
-> Hash (cost=100.87..100.87 rows=1 width=24) (actual
time=1249.985..1249.985 rows=0 loops=1)
-> Subquery Scan all_items (cost=15.05..100.87 rows=1
width=24) (actual time=5.583..1248.912 rows=566 loops=1)
-> Nested Loop Left Join (cost=15.05..100.86 rows=1
width=28) (actual time=5.581..1247.873 rows=566 loops=1)
Join Filter: (("outer".id)::text =
("inner".item_id)::text)
-> Index Scan using idx_tbl_item_item_type,
idx_tbl_item_item_type on tbl_item items (cost=0.00..84.16 rows=1 width=24)
(actual time=0.093..5.702 rows=566 loops=1)
Index Cond: (((item_type)::text =
'DIR'::text) OR ((item_type)::text = 'NET'::text))
Filter: ((NOT inactive) AND (item_class = 1))
-> Subquery Scan last_inventory
(cost=15.05..15.95 rows=60 width=28) (actual time=0.010..1.784 rows=445 loops=566)
-> Unique (cost=15.05..15.35 rows=60
width=32) (actual time=0.008..1.043 rows=445 loops=566)
-> Sort (cost=15.05..15.20 rows=60
width=32) (actual time=0.006..0.289 rows=445 loops=566)
Sort Key: tbl_data.item_id,
tbl_data.inventory_id
-> Hash Join (cost=1.30..13.28
rows=60 width=32) (actual time=0.117..1.675 rows=445 loops=1)
Hash Cond:
("outer".inventory_id = "inner".inventory_id)
-> Seq Scan on tbl_data
(cost=0.00..8.92 rows=492 width=28) (actual time=0.009..0.474 rows=445 loops=1)
-> Hash (cost=1.24..1.24
rows=24 width=8) (actual time=0.031..0.031 rows=0 loops=1)
-> Seq Scan on
tbl_detail (cost=0.00..1.24 rows=24 width=8) (actual time=0.014..0.017 rows=2
loops=1)
Total runtime: 1292.896 ms
(82 rows)
Here is the explain analyze output with the WHERE clause active.
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=646.74..646.74 rows=1 width=36) (actual
time=11422.145..11422.334 rows=147 loops=1)
-> Nested Loop (cost=57.11..646.74 rows=1 width=36) (actual
time=17.359..11420.069 rows=504 loops=1)
Join Filter: ((("outer".item_id)::text = ("inner".item_id)::text) AND
("inner".ship_date > "outer".inventory_date))
-> Subquery Scan all_items (cost=15.05..100.87 rows=1 width=28)
(actual time=5.494..1269.377 rows=566 loops=1)
-> Nested Loop Left Join (cost=15.05..100.86 rows=1 width=28)
(actual time=5.490..1267.843 rows=566 loops=1)
Join Filter: (("outer".id)::text = ("inner".item_id)::text)
-> Index Scan using idx_tbl_item_item_type,
idx_tbl_item_item_type on tbl_item items (cost=0.00..84.16 rows=1 width=24)
(actual time=0.094..6.970 rows=566 loops=1)
Index Cond: (((item_type)::text = 'DIR'::text) OR
((item_type)::text = 'NET'::text))
Filter: ((NOT inactive) AND (item_class = 1))
-> Subquery Scan last_inventory (cost=15.05..15.95
rows=60 width=28) (actual time=0.011..1.811 rows=445 loops=566)
-> Unique (cost=15.05..15.35 rows=60 width=32)
(actual time=0.008..1.052 rows=445 loops=566)
-> Sort (cost=15.05..15.20 rows=60
width=32) (actual time=0.006..0.289 rows=445 loops=566)
Sort Key: tbl_data.item_id,
tbl_data.inventory_id
-> Hash Join (cost=1.30..13.28
rows=60 width=32) (actual time=0.124..1.661 rows=445 loops=1)
Hash Cond: ("outer".inventory_id
= "inner".inventory_id)
-> Seq Scan on tbl_data
(cost=0.00..8.92 rows=492 width=28) (actual time=0.008..0.479 rows=445 loops=1)
-> Hash (cost=1.24..1.24
rows=24 width=8) (actual time=0.032..0.032 rows=0 loops=1)
-> Seq Scan on tbl_detail
(cost=0.00..1.24 rows=24 width=8) (actual time=0.015..0.018 rows=2 loops=1)
-> Subquery Scan all_shipped_items (cost=42.06..544.66 rows=80
width=40) (actual time=0.056..17.002 rows=884 loops=566)
-> Append (cost=42.06..543.86 rows=80 width=40) (actual
time=0.054..15.355 rows=884 loops=566)
-> Subquery Scan "*SELECT* 1" (cost=42.06..80.49 rows=1
width=32) (actual time=0.053..8.856 rows=376 loops=566)
-> Nested Loop (cost=42.06..80.48 rows=1
width=32) (actual time=0.050..8.131 rows=376 loops=566)
-> Hash Join (cost=42.06..74.62 rows=1
width=32) (actual time=0.034..4.011 rows=376 loops=566)
Hash Cond: (("outer".item_id)::text =
("inner".id)::text)
-> Seq Scan on tbl_line_item
(cost=0.00..27.37 rows=1037 width=32) (actual time=0.003..1.220 rows=1087
loops=566)
-> Hash (cost=42.06..42.06 rows=1
width=24) (actual time=4.029..4.029 rows=0 loops=1)
-> Index Scan using
idx_tbl_item_item_type on tbl_item (cost=0.00..42.06 rows=1 width=24) (actual
time=0.032..3.350 rows=502 loops=1)
Index Cond:
((item_type)::text = 'DIR'::text)
Filter: ((NOT inactive) AND
(item_class = 1))
-> Index Scan using tbl_detail_pkey on
tbl_detail (cost=0.00..5.84 rows=1 width=8) (actual time=0.005..0.006 rows=1
loops=212816)
Index Cond: ("outer".i_number =
tbl_detail.i_number)
-> Subquery Scan "*SELECT* 2" (cost=89.47..199.26
rows=56 width=36) (actual time=0.365..3.797 rows=460 loops=566)
-> Hash Join (cost=89.47..198.70 rows=56
width=36) (actual time=0.361..2.979 rows=460 loops=566)
Hash Cond: (("outer".id)::text =
("inner".item_id)::text)
-> Seq Scan on tbl_assembly
(cost=0.00..87.30 rows=4230 width=52) (actual time=0.335..0.931 rows=587
loops=566)
-> Hash (cost=89.46..89.46 rows=3 width=56)
(actual time=5.369..5.369 rows=0 loops=1)
-> Hash Join (cost=74.64..89.46
rows=3 width=56) (actual time=4.359..5.177 rows=137 loops=1)
Hash Cond: ("outer".i_number =
"inner".i_number)
-> Seq Scan on tbl_detail
(cost=0.00..13.53 rows=253 width=8) (actual time=0.004..0.353 rows=281 loops=1)
-> Hash (cost=74.63..74.63
rows=3 width=56) (actual time=4.307..4.307 rows=0 loops=1)
-> Hash Join
(cost=42.04..74.63 rows=3 width=56) (actual time=1.558..4.117 rows=137 loops=1)
Hash Cond:
(("outer".item_id)::text = ("inner".id)::text)
-> Seq Scan on
tbl_line_item (cost=0.00..27.37 rows=1037 width=32) (actual time=0.004..1.138
rows=1087 loops=1)
-> Hash
(cost=42.03..42.03 rows=5 width=24) (actual time=1.356..1.356 rows=0 loops=1)
-> Index Scan
using idx_tbl_item_item_type on tbl_item (cost=0.00..42.03 rows=5 width=24)
(actual time=0.034..1.089 rows=205 loops=1)
Index
Cond: ((item_type)::text = 'ASY'::text)
Filter:
(NOT inactive)
-> Subquery Scan "*SELECT* 3" (cost=89.66..116.32
rows=1 width=36) (actual time=0.052..1.441 rows=48 loops=566)
-> Nested Loop (cost=89.66..116.31 rows=1
width=36) (actual time=0.048..1.343 rows=48 loops=566)
-> Hash Join (cost=89.66..104.47 rows=2
width=38) (actual time=0.023..0.698 rows=48 loops=566)
Hash Cond: ("outer".so_number =
"inner".number)
-> Seq Scan on tbl_detail
(cost=0.00..13.53 rows=253 width=12) (actual time=0.003..0.333 rows=281 loops=566)
-> Hash (cost=89.66..89.66 rows=1
width=34) (actual time=4.781..4.781 rows=0 loops=1)
-> Hash Join (cost=84.17..89.66
rows=1 width=34) (actual time=4.281..4.695 rows=60 loops=1)
Hash Cond:
(("outer".item_id)::text = ("inner".id)::text)
-> Seq Scan on
tbl_item_bom (cost=0.00..4.32 rows=232 width=34) (actual time=0.008..0.096
rows=61 loops=1)
-> Hash
(cost=84.16..84.16 rows=1 width=24) (actual time=4.237..4.237 rows=0 loops=1)
-> Index Scan using
idx_tbl_item_item_type, idx_tbl_item_item_type on tbl_item (cost=0.00..84.16
rows=1 width=24) (actual time=0.033..3.470 rows=566 loops=1)
Index Cond:
(((item_type)::text = 'DIR'::text) OR ((item_type)::text = 'NET'::text))
Filter: ((NOT
inactive) AND (item_class = 1))
-> Index Scan using tbl_line_item_pkey on
tbl_line_item (cost=0.00..5.90 rows=1 width=10) (actual time=0.007..0.008
rows=1 loops=27168)
Index Cond: (("outer".i_number =
tbl_line_item.i_number) AND ("outer".line = tbl_line_item.i_line))
-> Subquery Scan "*SELECT* 4" (cost=47.54..147.80
rows=22 width=40) (actual time=0.166..0.166 rows=0 loops=566)
-> Nested Loop (cost=47.54..147.58 rows=22
width=40) (actual time=0.164..0.164 rows=0 loops=566)
-> Nested Loop (cost=47.54..74.18 rows=1
width=60) (actual time=0.162..0.162 rows=0 loops=566)
-> Hash Join (cost=47.54..62.35
rows=2 width=62) (actual time=0.161..0.161 rows=0 loops=566)
Hash Cond: ("outer".so_number =
"inner".number)
-> Seq Scan on tbl_detail
(cost=0.00..13.53 rows=253 width=12) (never executed)
-> Hash (cost=47.53..47.53
rows=1 width=58) (actual time=1.432..81.382 rows=0 loops=1)
-> Hash Join
(cost=42.04..47.53 rows=1 width=58) (actual time=1.430..80.405 rows=0 loops=1)
Hash Cond:
(("outer".item_id)::text = ("inner".id)::text)
-> Seq Scan on
tbl_item_bom (cost=0.00..4.32 rows=232 width=34) (actual time=0.004..39.690
rows=34526 loops=1)
-> Hash
(cost=42.03..42.03 rows=5 width=24) (actual time=1.278..1.278 rows=0 loops=1)
-> Index Scan
using idx_tbl_item_item_type on tbl_item (cost=0.00..42.03 rows=5 width=24)
(actual time=0.024..1.024 rows=205 loops=1)
Index
Cond: ((item_type)::text = 'ASY'::text)
Filter:
(NOT inactive)
-> Index Scan using tbl_line_item_pkey
on tbl_line_item (cost=0.00..5.90 rows=1 width=10) (never executed)
Index Cond: (("outer".i_number =
tbl_line_item.i_number) AND ("outer".line = tbl_line_item.i_line))
-> Index Scan using tbl_assembly_pkey on
tbl_assembly (cost=0.00..73.01 rows=22 width=52) (never executed)
Index Cond: (("outer".id)::text =
(tbl_assembly.id)::text)
Total runtime: 11423.492 ms
(81 rows)
Kind Regards,
Keith
On Sat, 19 Feb 2005, Keith Worthington wrote:
> On Fri, 18 Feb 2005 21:55:29 -0800 (PST), Stephan Szabo wrote
> > On Fri, 18 Feb 2005, Keith Worthington wrote:
> >
> > > I have been working on a SQL statement that contains a WHERE
> > > clause of the form WHERE column1 > column2. The query runs
> > > pretty quickly (285ms) without the WHERE clause but slows to
> > > a relative crawl (5850ms) when it is included.
> > > Any suggestions on how to improve the performance would be
> > > greatly appreciated.
> >
> > Explain analyze output for the query with and without the clause
> > would probably be useful for analysis.
>
> Here is the explain analyze output with the WHERE
> clause commented out. This one actually ran slow. Usually it is only a few
> hundred ms without the WHERE clause.
That's probably just the instrumentation.
I'm not 100% sure why it's changing plans although I wonder if the costs
are just close enough that small changes are causing the plan change, but
I think it wouldn't pick a nested loop if it knew that it was grossly
underestimating the number of loops. It might be interesting to see how
the second query runs in explain analyze with enable_nestloop=off although
that'll likely make lower portions of the query more expensive.
One thing that jumps out at me is scans like this:
-> Index Scan using idx_tbl_item_item_type,
idx_tbl_item_item_type on tbl_item items (cost=0.00..84.16 rows=1
width=24)
(actual time=0.093..5.702 rows=566 loops=1)
Index Cond: (((item_type)::text =
'DIR'::text) OR ((item_type)::text = 'NET'::text))
Filter: ((NOT inactive) AND (item_class = 1))
This misestimation may be playing a part in why it thinks a nested loop is
a good plan. Is there a strong correlation between some item_types and
item_class or inactive? What does explain analyze on the following
queries show?
select * from tbl_item where (item_type='DIR OR item_type='NET');
select * from tbl_item where (item_type='DIR OR item_type='NET') AND NOT
inactive;
select * from tbl_item where (item_type='DIR OR item_type='NET') AND
item_class=1;
select * from tbl_item where (item_type='DIR OR item_type='NET') AND NOT
inactive AND item_class=1;
I'm not sure if you'd get any win from a partial index with WHERE NOT
inactive (or possibly both NOT inactive AND item_class=1 if you're almost
always limiting item_class to 1), but that might also be something to
check.