use*_*724 9 postgresql indexing query-optimization database-partitioning postgresql-performance
我有以下表和索引定义:
CREATE TABLE ticket
(
wid bigint NOT NULL DEFAULT nextval('tickets_id_seq'::regclass),
eid bigint,
created timestamp with time zone NOT NULL DEFAULT now(),
status integer NOT NULL DEFAULT 0,
argsxml text,
moduleid character varying(255),
source_id bigint,
file_type_id bigint,
file_name character varying(255),
status_reason character varying(255),
...
)
Run Code Online (Sandbox Code Playgroud)
我在created
时间戳上创建了一个索引,如下所示:
CREATE INDEX ticket_1_idx
ON ticket
USING btree
(created );
Run Code Online (Sandbox Code Playgroud)
这是我的疑问
select * from ticket
where created between '2012-12-19 00:00:00' and '2012-12-20 00:00:00'
Run Code Online (Sandbox Code Playgroud)
这个工作正常,直到记录数量开始增长(约500万),现在它将永远回归.
解释分析揭示了这一点:
"Index Scan using ticket_1_idx on ticket (cost=0.00..10202.64 rows=52543 width=1297) (actual time=0.109..125.704 rows=53340 loops=1)"
" Index Cond: ((created >= '2012-12-19 00:00:00+00'::timestamp with time zone) AND (created <= '2012-12-20 00:00:00+00'::timestamp with time zone))"
"Total runtime: 175.853 ms"
Run Code Online (Sandbox Code Playgroud)
到目前为止,我已经尝试过设置
random_page_cost = 1.75
effective_cache_size = 3
Run Code Online (Sandbox Code Playgroud)
也创建了
create CLUSTER ticket USING ticket_1_idx;
Run Code Online (Sandbox Code Playgroud)
什么都行不通.我究竟做错了什么?为什么选择顺序扫描?索引应该使查询快速.有什么可以做的来优化它吗?
Erw*_*ter 21
CLUSTER
如果您打算使用CLUSTER
,则显示的语法无效.
create CLUSTER ticket USING ticket_1_idx;
运行一次:
CLUSTER ticket USING ticket_1_idx;
Run Code Online (Sandbox Code Playgroud)
对于更大的结果集,这可以帮助很多.返回单行并非如此.
Postgres会记住用于后续调用的索引.如果您的表格不是只读的,则效果会随着时间的推移而恶化,您需要以一定的间隔重新运行:
CLUSTER ticket;
Run Code Online (Sandbox Code Playgroud)
可能只在易失性分区上.见下文.
但是,如果您有大量更新,CLUSTER
(或VACUUM FULL
)可能实际上不利于性能.适量的膨胀允许UPDATE
在同一数据页面上放置新的行版本,并且避免了太频繁地在OS中物理扩展底层文件的需要.您可以使用经过精心调整FILLFACTOR
以获得两全其美的效果:
pg_repack
CLUSTER
对表进行独占锁定,这可能是多用户环境中的问题.引用手册:
当表正在聚集时,
ACCESS EXCLUSIVE
会在其上获取锁.这可以防止任何其他数据库操作(读取和写入)在表上运行,直到CLUSTER
完成为止.
大胆强调我的.考虑替代方案pg_repack
:
与在线工作不同
CLUSTER
,VACUUM FULL
在处理过程中不对待处理的表进行独占锁定.pg_repack的启动效率很高,性能可与CLUSTER
直接使用相媲美.
和:
pg_repack需要在重组结束时进行独占锁定.
版本1.3.1适用于:
PostgreSQL 8.3,8.4,9.0,9.1,9.2,9.3,9.4
版本1.4.2适用于:
PostgreSQL 9.1,9.2,9.3,9.4,9.5,9.6,10
查询很简单,不会导致任何性能问题.
但是,关于正确性的一个词:该BETWEEN
构造包括边界.您的查询将选择12月19日的所有内容,以及 12月20日00:00时的记录.这是一个非常不可能的要求.机会是,你真的想要:
SELECT *
FROM ticket
WHERE created >= '2012-12-19 0:0'
AND created < '2012-12-20 0:0';
Run Code Online (Sandbox Code Playgroud)
首先,你问:
为什么选择顺序扫描?
您的EXPLAIN
输出清楚地显示了索引扫描,而不是顺序表扫描.必定存在某种误解.
如果你为了更好的表现而努力,你可能会改进.但是必要的背景信息不在问题中.可能的选择包括:
您只能查询所需的列而不是*
降低传输成本(以及可能的其他性能优势).
您可以查看分区并将实际时间片放入单独的表中.根据需要向分区添加索引.
如果分区不是一个选项,则另一个相关但较少侵入性的技术是添加一个或多个部分索引.
例如,如果您主要查询当前月份,则可以创建以下部分索引:
CREATE INDEX ticket_created_idx ON ticket(created)
WHERE created >= '2012-12-01 00:00:00'::timestamp;
Run Code Online (Sandbox Code Playgroud)
CREATE
在新月开始之前的新指数.您可以使用cron作业轻松自动执行任务.可选择DROP
旧月的部分索引.
另外保留总索引CLUSTER
(不能对部分索引进行操作).如果旧记录永远不会更改,表分区将对此任务有很大帮助,因为您只需要重新集群较新的分区.然后,如果记录永远不会改变,你可能不需要CLUSTER
.
如果你结合最后两个步骤,性能应该是很棒的.
您可能遗漏了其中一个基础知识.所有通常的性能建议都适用:
归档时间: |
|
查看次数: |
12633 次 |
最近记录: |