以Postgresql为主,再聊聊资料库 巧用 array 处理 tags

PostgreSQL 巧用 array 处理 tags

在许多系统中,会使用tag,或是属性.
我们将介绍传统的方式,以及PostgreSQL 的 array 两种方式.

传统方式

会建立三个table,一个用来放标的,一个用来放tag,一个用来放中介.

create table videos (  vid_id int not null generated always as identity primary key, vid_number text not null);create table tags (  tag_id int not null generated always as identity primary key, tag_name text not null, unique(tag_name));create table video_tags (  vid_id int not null, tag_id int not null, unique(vid_id, tag_id));--测试资料insert into videos(vid_number)values ('MEYD-844'), ('WAAA-293');insert into tags (tag_name)values ('熟女'),('人妻'),('巨乳'),('泳装'),       ('单体作品'),('高清'),('独家'),('4K'),       ('女教师'),('痴女'),('大屁股'),('中出');insert into video_tags values(1, 1), (1, 2), (1, 3), (1, 4),(1, 5), (1, 6), (1, 7), (1, 8),(2, 9), (2, 10),(2, 11), (2, 12),(2, 3), (2, 1), (2, 8), (2, 7);

查询的方式

一个 tag 的情况

select v.vid_number  from videos v  join video_tags vt    on (v.vid_id = vt.vid_id)  join tags t    on (vt.tag_id = t.tag_id) where t.tag_name = '女教师';   vid_number ------------ WAAA-293

两个 tag 的情况

select v.vid_number  from videos v  join video_tags vt1    on (v.vid_id = vt1.vid_id)  join video_tags vt2    on (vt1.vid_id = vt2.vid_id)  join tags t1    on (vt1.tag_id = t1.tag_id)  join tags t2    on (vt2.tag_id = t2.tag_id) where t1.tag_name = '熟女'   and t2.tag_name = '巨乳';    vid_number ------------ MEYD-844 WAAA-293(2 rows)

三个 tag 的情况

select v.vid_number  from videos v  join video_tags vt1    on (v.vid_id = vt1.vid_id)  join video_tags vt2    on (vt1.vid_id = vt2.vid_id)  join video_tags vt3    on (vt2.vid_id = vt3.vid_id)  join tags t1    on (vt1.tag_id = t1.tag_id)  join tags t2    on (vt2.tag_id = t2.tag_id)  join tags t3    on (vt3.tag_id = t3.tag_id) where t1.tag_name = '熟女'   and t2.tag_name = '巨乳'   and t3.tag_name = '泳装'; vid_number ------------ MEYD-844

由上面的例子可以看到,查询方式较为繁琐.

使用array的方式

这时只需要两个 table,tags 还是一样,将中介的 table video_tags
合併进 videos 产生新的 videos_array

create table videos_array (  vid_id int not null primary key, vid_number text not null, vid_tags int[]);insert into videos_arrayselect v.vid_id, vid_number, array_agg(tag_id)  from videos v  join video_tags  using (vid_id)  group by v.vid_id, vid_number;  select *  from videos_array; vid_id | vid_number |       vid_tags       --------+------------+----------------------      1 | MEYD-844   | {1,2,3,4,5,6,7,8}      2 | WAAA-293   | {1,3,7,8,9,10,11,12}(2 rows)--可以建立GIN indexcreate index on videos_array using gin (vid_tags);

查询的方式

---三个 tag 的情况with t1 as MATERIALIZED (select array_agg(tag_id) as tag_ids  from tags where tag_name in ('熟女', '巨乳', '泳装'))select va.vid_number  from videos_array va  join t1    on va.vid_tags @> t1.tag_ids; vid_number ------------ MEYD-844

当我们需要查询具有多个tag,只要善用array 的包含运算子 @>
以及 array_agg() 函数,透过 MATERIALIZED 型态 CTE(只计算一次),
即可方便撰写SQL,执行速度又快,因为资料笔数精简又不必透过中介table
多次join.

查询单一 video 的 tag_name

可以使用 unnest() 展开 array

select t.tag_name  from videos_array va  cross join unnest(va.vid_tags) as tag_id  join tags t using (tag_id) where va.vid_number = 'MEYD-844'; tag_name ---------- 熟女 人妻 巨乳 泳装 单体作品 高清 独家 4K(8 rows)

结语

PostgreSQL的Array,是一个成熟并具有弹性,可以让我们精简查询,减少空间,有效的反正规化,提高查询速度的好东西,可以多加利用.

致谢

感谢佐山爱小姐.

同步发表

本文同步发表于 https://hackmd.io/@pgsql-tw/rJSOHh8zT


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章