【发布时间】:2021-02-24 06:36:27
【问题描述】:
所以我有这个查询;
SELECT
*
FROM
api_points
WHERE
cat_level_5 = ANY(ARRAY['7223b580c20758c7','3e23543ccb9a2ef4','bbaec92cedb8a3bc',...])
AND
NOT cat_level_5 = ANY(ARRAY['8ccb9d2231a318e4'])
关于地理空间点的记录大约有 2~300 万条。类别是分层的,有 5 列命名为 cat_level_1、cat_level_2、cat_level_3、cat_level_4 和 cat_level_5。
此查询指定了许多 5 级类别,大约需要 1-2 分钟才能完成。我从使用 IN 运算符切换到使用数组的 =。
我可以更改类别结构或类别数据类型以加快索引速度。
顺便说一句,当我使用 btree(cat_level_1, cat_level_2, cat_level_3, cat_level_4, cat_level_5) 添加索引时,它并没有太大的区别。
这里是result of EXPLAIN(ANALYZE, BUFFERS)
编辑
我对此进行了 SQL 查询编辑,结果为this。
EXPLAIN (ANALYZE, BUFFERS)
SELECT *
FROM (
SELECT * FROM unnest(ARRAY['7223b580c20758c7','3e23543ccb9a2ef4','bbaec92cedb8a3bc',...]) cat_level_5
WHERE cat_level_5 NOT IN ( SELECT * FROM unnest(ARRAY['8ccb9d2231a318e4']) )
) categories
JOIN api_point
USING (cat_level_5)
表结构由这个django模型定义;
class Point(models.Model):
poi_id = models.TextField(primary_key=True)
poi_name = models.TextField(default = "")
poi_address = models.TextField(default = "")
location = models.TextField(default = "")
location_info = models.TextField(default = "")
history = models.DateField(default = datetime.date.today)
city_code = models.IntegerField()
town_code = models.IntegerField()
quarter_code = models.IntegerField()
icon_url = models.TextField()
cat_level_1 = models.TextField()
cat_level_1_name = models.TextField()
cat_level_2 = models.TextField()
cat_level_2_name = models.TextField()
cat_level_3 = models.TextField()
cat_level_3_name = models.TextField()
cat_level_4 = models.TextField()
cat_level_4_name = models.TextField()
cat_level_5 = models.TextField()
cat_level_5_name = models.TextField()
lat = models.FloatField()
lon = models.FloatField()
point = PointField(default = Point(0.0, 0.0))
last_modified = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
SQL表结构如下:
CREATE TABLE public.api_poi
(
poi_id text COLLATE pg_catalog."default" NOT NULL,
poi_name text COLLATE pg_catalog."default" NOT NULL,
poi_address text COLLATE pg_catalog."default" NOT NULL,
location text COLLATE pg_catalog."default" NOT NULL,
location_info text COLLATE pg_catalog."default" NOT NULL,
history date NOT NULL,
city_code integer NOT NULL,
town_code integer NOT NULL,
quarter_code integer NOT NULL,
icon_url text COLLATE pg_catalog."default" NOT NULL,
lat double precision NOT NULL,
lon double precision NOT NULL,
last_modified timestamp with time zone NOT NULL,
created_at timestamp with time zone NOT NULL,
point geometry(Point,4326) NOT NULL,
cat_level_1 text COLLATE pg_catalog."default" NOT NULL,
cat_level_1_name text COLLATE pg_catalog."default" NOT NULL,
cat_level_2 text COLLATE pg_catalog."default" NOT NULL,
cat_level_2_name text COLLATE pg_catalog."default" NOT NULL,
cat_level_3 text COLLATE pg_catalog."default" NOT NULL,
cat_level_3_name text COLLATE pg_catalog."default" NOT NULL,
cat_level_4 text COLLATE pg_catalog."default" NOT NULL,
cat_level_4_name text COLLATE pg_catalog."default" NOT NULL,
cat_level_5 text COLLATE pg_catalog."default" NOT NULL,
cat_level_5_name text COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT api_poi_pkey PRIMARY KEY (poi_id)
)
TABLESPACE pg_default;
ALTER TABLE public.api_poi
OWNER to postgres;
-- Index: category_idx
-- DROP INDEX public.category_idx;
CREATE INDEX category_idx
ON public.api_poi USING btree
(cat_level_1 COLLATE pg_catalog."default" ASC NULLS LAST, cat_level_2 COLLATE pg_catalog."default" ASC NULLS LAST, cat_level_3 COLLATE pg_catalog."default" ASC NULLS LAST, cat_level_4 COLLATE pg_catalog."default" ASC NULLS LAST, cat_level_5 COLLATE pg_catalog."default" ASC NULLS LAST)
TABLESPACE pg_default;
-- Index: point_namex
-- DROP INDEX public.point_namex;
CREATE INDEX point_idx
ON public.api_poi USING brin
(point)
TABLESPACE pg_default;
【问题讨论】:
-
如果没有
EXPLAIN (ANALYZE, BUFFERS)输出,很难给出一个有根据的答案。您是否查看过ltree扩展及其索引支持来为您的层次结构建模? -
抱歉,我会尽快添加输出,我添加了 ltree 扩展,但我不确定它是否会有所作为;如果我只使用第 5 级进行搜索,那么它在那个状态下是分层的吗?
-
你好,我添加了
EXPLAIN(ANALYZE, BUFFERS)的结果。 -
什么工具以这种方式格式化解释分析输出并删除行估计?无论如何,这个查询看起来返回了大量的行(1962475),并且“过滤器删除的行数”暗示它选择了 88% 的表。
-
这看起来不像是 EXPLAIN ANALYZE,它没有显示执行此查询所花费的时间。除了也缺少的其他信息。
标签: django postgresql query-optimization