5 postgresql optimization order-by
我在一个大约有 300,000 行且每列都有 B 树的表上遇到了缓慢的性能。
这适用于动态分页页面,其中查询是按需构建的,并且应用程序按照查询的指定顺序缓存主键。
对于此查询
explain analyze
SELECT supplier_management.buyer_purchase_order_id
FROM supplier_management
ORDER BY item_description DESC,
item_number DESC,
order_type ASC,
possession_date DESC,
shipment_type DESC,
store_type DESC
Run Code Online (Sandbox Code Playgroud)
我得到这些结果:
排序(成本=51026.98..51750.35行=289348宽度=72)(实际时间=8229.280..12349.596行=289348循环=1)
排序键:商品描述、商品编号、订单类型、拥有日期、发货类型、商店类型
排序方式:外部合并磁盘:24744kB
-> 供应商管理上的顺序扫描(成本=0.00..10876.48行=289348宽度=72)(实际时间=0.015..187.426行=289348循环=1)
总运行时间:12407.064 毫秒
如何提高多列排序的性能?或者我应该用 C++ 来做?
buyer_purchase_order_id bigint
supplier_number bigint
supplier_name character varying
purchase_order_number bigint
store_number integer
item_number bigint
item_description character varying
project_type character varying
order_date integer
requested_arrival_date integer
department character varying
store_type character varying
shipment_type character varying
order_type character varying
quantity_ordered integer
quantity_allocation integer
quantity_staged integer
quantity_shipped integer
quantity_received integer
in_stock_date integer
in_stock_date_visible_on integer
show_red boolean
requested_arrival_date_plus_four_business_days integer
supplier_status character varying
notes_comments character varying
requested_arrival_date_color character varying
grand_opening_date integer
possession_date integer
consolidator_name character varying
real_requested_arrival_date_plus_four_business_days integer
Run Code Online (Sandbox Code Playgroud)
不character varying
超过索引的长度限制;然而,存在一些重复。将实际值放入另一个表中,进行规范化并连接到相关的整数列会更有效吗?
您可以做一些事情:
尽可能使用按值或简单字段作为键的enum
s或查找,而不是 varchar 排序键。我会使用 an 因为您可以轻松控制排序顺序。integer
"char"
enum
枚举唯一严重的缺点是您当前无法从枚举类型中删除值。您可以添加它们(包括将它们插入排序顺序的中间),但不能删除它们。如果这是一个问题,您将需要使用查找表,或者仅声明"char"
具有单字符代码的字段。
另外,如果您不需要正确的语言排序规则,请指定COLLATE "C"
字符字段,例如
CREATE INDEX itemdesc_c ON supplier_management (item_description ASC COLLATE "C");
Run Code Online (Sandbox Code Playgroud)
进而:
ORDER BY ...
itemdesc COLLATE "C",
...
Run Code Online (Sandbox Code Playgroud)
需要注意的重要事项:
WHERE
Pg 可以组合谓词(子句等)的索引,但不能排序。您不能使用位图索引扫描进行排序。因此它最多可以使用一个候选索引,然后它必须对每组内的行进行排序。
低选择性索引是浪费时间。如果值分布不广,则不要对该列建立索引。
Pg 正在执行磁盘排序。在问题上投入更多的记忆 - 尝试SET work_mem = '20MB'
开始。但请参阅下面我的评论,重新与 high 进行斗争max_connections
。使用连接池。
使用连接池。
索引是有代价的——它们会减慢插入/更新/删除速度并增加真空工作。因此,如果索引没有被大量使用,请将其删除。
pg_catalog.pg_stat_user_indexes
将帮助您判断使用了哪些索引。
pg_stat_statements
(在 contrib 中)和pg_stat_plans
(后者是外部模块)对于捕获有关查询模式、慢速查询等的数据非常有用。
学会爱上这个auto_explain
模块。
另外,如果您总是进行这种排序,创建一个复合索引来匹配它也会有所帮助。
CREATE INDEX bigindex ON supplier_management (
item_description DESC,
item_number DESC,
order_type ASC,
possession_date DESC,
shipment_type DESC,
store_type DESC
);
Run Code Online (Sandbox Code Playgroud)
...但请注意,它仅对这种特定的排序有用,并且它将是一个很大的索引,因此只有当您经常这样做时才值得拥有。事实上,您也可以添加supplier_management.buyer_purchase_order_id
,这样它就可以进行仅索引扫描:
CREATE INDEX bigindex ON supplier_management (
item_description DESC,
item_number DESC,
order_type ASC,
possession_date DESC,
shipment_type DESC,
store_type DESC,
buyer_purchase_order_id
);
Run Code Online (Sandbox Code Playgroud)