说到在PostgreSQL里优化函数,通常主要有两个核心点:索引和分区。这两招能让你处理大数据时更快,少做无用功,查数据也能“直奔主题”。下面咱们详细聊聊。
数据库里的索引其实就像书的目录。你找内容时不会一页页翻,而是看目录,找到主题直接跳页。PostgreSQL里的索引也是这么干的。
创建索引
索引用CREATE INDEX命令建。举个简单例子:
-- 在users表的id列上建索引,加速查找
CREATE INDEX idx_users_id ON users (id);
现在,如果你执行类似这样的查询:
SELECT * FROM users WHERE id = 42;
PostgreSQL会用你刚建的索引,飞快地找到那一行。
例子:用索引优化函数
假设我们有个函数,要从orders表里查某个用户的订单:
CREATE OR REPLACE FUNCTION get_user_orders(user_id INT)
RETURNS TABLE(order_id INT, order_date DATE) AS $$
BEGIN
RETURN QUERY
SELECT id, order_date
FROM orders
WHERE user_id = user_id;
END;
$$ LANGUAGE plpgsql;
如果orders表有几百万行,这函数跑起来会很慢。咋办?在user_id上建个索引:
CREATE INDEX idx_orders_user_id ON orders (user_id);
这样函数里的查询就会快很多,因为PostgreSQL会用索引来找行。
索引的类型
PostgreSQL支持好几种索引,最常用的是B-TREE和GIN。简单对比如下:
| 索引类型 | 用途 | 例子 |
|---|---|---|
B-TREE |
标准查找用的索引。 | 查数字、字符串(=, >, <)。 |
GIN |
全文检索或JSON用。 | 查数组、JSONB。 |
想深入了解索引,可以看看PostgreSQL官方文档。
数据分区
索引是查找加速器,分区则是把大表拆成小块(分区)。当你一张表里有巨量数据时,这招特别有用。
比如你有个orders表,存了10年订单。如果你查最近一个月的订单,PostgreSQL默认还是会扫全表,挺费劲。分区能解决这问题,比如按年拆分。
创建分区表
你可以这样建分区表:
-- 创建orders表为父分区表
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
order_date DATE NOT NULL,
user_id INT NOT NULL
) PARTITION BY RANGE (order_date);
-- 为每年建子表
CREATE TABLE orders_2023 PARTITION OF orders FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
CREATE TABLE orders_2022 PARTITION OF orders FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');
现在你查类似这样的数据:
SELECT * FROM orders WHERE order_date >= '2023-01-01' AND order_date < '2023-02-01';
PostgreSQL会立刻知道只用查orders_2023,不用全表遍历。
在函数里用分区
假如我们有个函数,要查某一年的订单。因为用了分区,函数里的查询会快很多,因为PostgreSQL只查对应的子表。
CREATE OR REPLACE FUNCTION get_orders_by_year(year INT)
RETURNS TABLE(order_id INT, order_date DATE) AS $$
BEGIN
RETURN QUERY
SELECT id, order_date
FROM orders
WHERE order_date >= make_date(year, 1, 1)
AND order_date < make_date(year + 1, 1, 1);
END;
$$ LANGUAGE plpgsql;
实战案例
- 索引案例
按字符串查找:比如你有个商品表,经常按名字查商品,就在name字段上建索引:
CREATE INDEX idx_products_name ON products (name);
加速排序:如果经常按日期排序查询,也建个索引:
CREATE INDEX idx_orders_date ON orders (order_date);
- 分区案例
历史数据:如果表里有时间戳,按天、月或年分区能大大加快查询。
地理数据:如果表里有国家字段,可以按国家分区。
常见坑和解决办法
很多开发者会犯一个错,就是建太多索引。这样会导致插入和更新变慢,因为每次表变了,PostgreSQL都得更新索引。建议:只在你经常用来查条件或排序的字段上建索引。
还有一个常见坑是分区分得太细,比如按天分而不是按月,这样会让表管理变得很麻烦,性能反而不好。
GO TO FULL VERSION