为什么 PREPARE 语句不尊重 INDEXing
why does PREPARE statement not respect INDEXing
帮助我理解为什么使用预处理语句评估的查询不遵守索引。
\d+ lerg;
Table "public.lerg"
Column | Type | Modifiers | Storage | Stats target | Description
------------+-----------------------------+---------------------------------------------------+----------+--------------+-------------
id | bigint | not null default nextval('lerg_id_seq'::regclass) | plain | |
lata | character varying | not null | extended | |
npa | character varying(3) | | extended | |
nxx | character varying(3) | | extended | |
block | character varying(1) | | extended | |
ocn | character varying | | extended | |
created_at | timestamp without time zone | not null default now() | plain | |
Indexes:
"lerg_pkey" PRIMARY KEY, btree (id)
"lerg_npa_nxx_block" UNIQUE, btree (npa, nxx, block)
LERG
table.
中的记录总数
select count(*) from lerg;
=> 199846
准备好的语句
prepare fetch_lata(char(3), char(3), char(1)) as select lata from lerg where npa= and nxx= and block=;
执行语句。
explain analyze execute fetch_lata('365','406','A');
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------
Seq Scan on lerg (cost=0.00..5163.31 rows=1 width=6) (actual time=0.014..27.530 rows=1 loops=1)
Filter: (((npa)::bpchar = '365'::bpchar) AND ((nxx)::bpchar = '406'::bpchar) AND ((block)::bpchar = 'A'::bpchar))
Rows Removed by Filter: 199845
Execution time: 27.560 ms
(4 rows)
看不懂。
- 为什么 table 扫描?
- 为什么不使用索引?
其他说明。
explain analyze select lata from lerg where npa='365' and nxx='406' and block='A';
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
Index Scan using lerg_npa_nxx_block on lerg (cost=0.42..8.44 rows=1 width=6) (actual time=0.016..0.016 rows=1 loops=1)
Index Cond: (((npa)::text = '365'::text) AND ((nxx)::text = '406'::text) AND ((block)::text = 'A'::text))
Planning time: 0.081 ms
Execution time: 0.033 ms
(4 rows)
Q. 具有适当索引的 select
查询胜过准备好的语句查询,为什么?
Q. 像上面这样的简单查询,使用PREPARED
语句没有优势吗?
请注意,查询 10_000 记录的差异太大,我不得不放弃准备好的语句。
查询10_000条记录的结果。
user system total real
pg_without_prepared_statmt 0.050000 0.080000 0.130000 ( 0.935051)
pg_with_prepared_statmt 0.090000 0.110000 0.200000 ( 5.707693)
机器详情。
Postgres Version : 9.5.9
Mac OS: 10.12.5
问题是你的准备语句的参数是character
类型(与bpchar
相同),所以使用了那个类型的相等运算符,不能使用索引因为它是用 character varying
.
定义的
如果将准备好的语句的参数更改为 varchar
,它应该会按预期工作。
帮助我理解为什么使用预处理语句评估的查询不遵守索引。
\d+ lerg;
Table "public.lerg"
Column | Type | Modifiers | Storage | Stats target | Description
------------+-----------------------------+---------------------------------------------------+----------+--------------+-------------
id | bigint | not null default nextval('lerg_id_seq'::regclass) | plain | |
lata | character varying | not null | extended | |
npa | character varying(3) | | extended | |
nxx | character varying(3) | | extended | |
block | character varying(1) | | extended | |
ocn | character varying | | extended | |
created_at | timestamp without time zone | not null default now() | plain | |
Indexes:
"lerg_pkey" PRIMARY KEY, btree (id)
"lerg_npa_nxx_block" UNIQUE, btree (npa, nxx, block)
LERG
table.
select count(*) from lerg;
=> 199846
准备好的语句
prepare fetch_lata(char(3), char(3), char(1)) as select lata from lerg where npa= and nxx= and block=;
执行语句。
explain analyze execute fetch_lata('365','406','A');
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------
Seq Scan on lerg (cost=0.00..5163.31 rows=1 width=6) (actual time=0.014..27.530 rows=1 loops=1)
Filter: (((npa)::bpchar = '365'::bpchar) AND ((nxx)::bpchar = '406'::bpchar) AND ((block)::bpchar = 'A'::bpchar))
Rows Removed by Filter: 199845
Execution time: 27.560 ms
(4 rows)
看不懂。
- 为什么 table 扫描?
- 为什么不使用索引?
其他说明。
explain analyze select lata from lerg where npa='365' and nxx='406' and block='A';
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
Index Scan using lerg_npa_nxx_block on lerg (cost=0.42..8.44 rows=1 width=6) (actual time=0.016..0.016 rows=1 loops=1)
Index Cond: (((npa)::text = '365'::text) AND ((nxx)::text = '406'::text) AND ((block)::text = 'A'::text))
Planning time: 0.081 ms
Execution time: 0.033 ms
(4 rows)
Q. 具有适当索引的 select
查询胜过准备好的语句查询,为什么?
Q. 像上面这样的简单查询,使用PREPARED
语句没有优势吗?
请注意,查询 10_000 记录的差异太大,我不得不放弃准备好的语句。
查询10_000条记录的结果。
user system total real
pg_without_prepared_statmt 0.050000 0.080000 0.130000 ( 0.935051)
pg_with_prepared_statmt 0.090000 0.110000 0.200000 ( 5.707693)
机器详情。
Postgres Version : 9.5.9
Mac OS: 10.12.5
问题是你的准备语句的参数是character
类型(与bpchar
相同),所以使用了那个类型的相等运算符,不能使用索引因为它是用 character varying
.
如果将准备好的语句的参数更改为 varchar
,它应该会按预期工作。