PostgreSQL总结(2)特殊数据类型查询 - array
2016-08-29 18:06
316 查看
回顾
前面我们介绍了PostgreSQL的安装和对数据库的一些简单操作。我们知道,对于数据库的大部分操作都是查询操作,PostgreSQL具有丰富的数据类型,有一些特殊的数据类型操作与其他关系型数据库有所区别,这里我们来介绍一下对于这些数据类型的查询。array查询
若Table_A和Table_B是多对多的关系,在其他关系型数据库中,我们会再创建一张表来保存Table_A与Table_B之间的关系,因为其他关系型数据库无法使用一条记录来保存这种关系。而在PostgreSQL中,则可以在Table_A和Table_B中分别使用一个数组来保存这种关系,就不需要额外的再创建一张表:在 Table_A 中字段 Column_A_B 是数组类型,Column_A_B 数组中的元素作为 Table_B 的外键;在 Table_B 中字段 Column_B_A 是数组类型,Column_B_A 数组中的元素作为 Table_A 的外键。为了更加直观,我们举例说明。有两张表:学生表(student)和课程表(course),一个学生可以选多门课程,一门课程被多个学生选。
-- 学生表 CREATE TABLE student ( id bigserial, --主键 name text, --姓名 courses bigint[], --所选课程 CONSTRAINT student_pk PRIMARY KEY(id) ); -- 课程表 CREATE TABLE course ( id bigserial, --主键 name text, --课程名称 e_name text, --课程英文名称 students bigint[], --选该课程的学生 CONSTRAINT course_pk PRIMARY KEY(id) );
在student表和course表中分别插入几条数据:
-- student插入四条数据 INSERT INTO student (name, courses) VALUES ('ZhangSan', array[1,2]), ('LiSi', array[1,3]), ('WangWu', array[2,3]), ('ZhaoLiu', array[1,2,3]); -- course插入三条数据 INSERT INTO course (name, e_name, students) VALUES ('语文', 'Chinese', array[1,2,4]), ('数学', 'Math', array[1,3,4]), ('英语', 'English', array[2,3,4]);
插入结果如下:
=> SELECT * FROM student; id | name | courses ----+----------+--------- 1 | ZhangSan | {1,2} 2 | LiSi | {1,3} 3 | WangWu | {2,3} 4 | ZhaoLiu | {1,2,3} (4 rows) => SELECT * FROM course; id | name | e_name | students ----+------+---------+---------- 1 | 语文 | Chinese | {1,2,4} 2 | 数学 | Math | {1,3,4} 3 | 英语 | English | {2,3,4} (3 rows)
目前在student表和course表中都只是保存了其关联的另一张表的id。那么问题来了,如果想查看其关联的表中的其他信息呢?如:想查看”ZhangSan”选了的课程名称有哪些?这就需要使用PostgreSQL中的关键词ANY了(或者使用”&&”)
SELECT s.id sid, c.id cid, s.name sname, s.courses, c.name cname, c.e_name ce_name FROM student s LEFT JOIN course c ON c.id = ANY(s.courses) ORDER BY s.id;
或者:
SELECT s.id sid, c.id cid, s.name sname, s.courses, c.name cname, c.e_name ce_name FROM student s LEFT JOIN course c ON array[c.id] && s.courses ORDER BY s.id;
查询结果如下:
sid | cid | sname | courses | cname | ce_name -----+-----+----------+---------+-------+--------- 1 | 1 | ZhangSan | {1,2} | 语文 | Chinese 1 | 2 | ZhangSan | {1,2} | 数学 | Math 2 | 1 | LiSi | {1,3} | 语文 | Chinese 2 | 3 | LiSi | {1,3} | 英语 | English 3 | 2 | WangWu | {2,3} | 数学 | Math 3 | 3 | WangWu | {2,3} | 英语 | English 4 | 1 | ZhaoLiu | {1,2,3} | 语文 | Chinese 4 | 2 | ZhaoLiu | {1,2,3} | 数学 | Math 4 | 3 | ZhaoLiu | {1,2,3} | 英语 | English
但这个结果好像跟我们预期的还有那么一点点不一样:我们希望的是,关联后的结果条数和student表相同(如分页查询学生所选课程),课程名称也是一个数组并且和课程的id数组对应。在这里,我们做一些改动,查询语句如下:
SELECT s.id sid, s.name sname, s.courses, array(SELECT name FROM course WHERE id = ANY(s.courses)) cname, array(SELECT e_name FROM course WHERE id = ANY(s.courses)) ce_name FROM student s ORDER BY s.id;
查询结果如下:
sid | sname | courses | cname | ce_name -----+----------+---------+------------------+------------------------ 1 | ZhangSan | {1,2} | {语文,数学} | {Chinese,Math} 2 | LiSi | {1,3} | {语文,英语} | {Chinese,English} 3 | WangWu | {2,3} | {数学,英语} | {Math,English} 4 | ZhaoLiu | {1,2,3} | {语文,数学,英语} | {Chinese,Math,English} (4 rows)
是不是这样的结果更能让人接受?但是问题又来了:如果course表中有很多个字段,都需要像上面那样合并成一个,那岂不是要有N多个子查询?这样会不会效率很低?关于这个问题,笔者也没有什么太好的解决方案,欢迎大家提出更好的解决方案。目前的处理方式是创建一个视图,将这些信息组合的耗时操作集中处理,不会影响用户。视图的DDL如下:
CREATE VIEW course_info AS SELECT DISTINCT courses, array(SELECT name FROM course WHERE id = ANY(s.courses)) cname, array(SELECT e_name FROM course WHERE id = ANY(s.courses)) ce_name FROM student s;
那么,在进行关联查询的时候,student表就直接和视图course_info进行关联,查询语句如下:
SELECT s.id sid, s.name sname, s.courses, ci.cname,ci.ce_name FROM student s LEFT JOIN course_info ci ON s.courses = ci.courses ORDER BY s.id;
我们来看看使用视图作为关联和不使用的情况的执行效率对比:
student表与course表关联:
EXPLAIN ANALYZE SELECT s.id sid, s.name sname, s.courses, array(SELECT name FROM course WHERE id = ANY(s.courses)) cname, array(SELECT e_name FROM course WHERE id = ANY(s.courses)) ce_name FROM student s ORDER BY s.id;
执行计划运行结果如下:
QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------- Sort (cost=32444.80..32446.80 rows=800 width=72) (actual time=0.114..0.115 rows=4 loops=1) Sort Key: s.id Sort Method: quicksort Memory: 26kB -> Seq Scan on student s (cost=0.00..32406.22 rows=800 width=72) (actual time=0.051..0.101 rows=4 loops=1) SubPlan 1 -> Bitmap Heap Scan on course (cost=9.59..20.24 rows=10 width=32) (actual time=0.010..0.011 rows=2 loops=4) Recheck Cond: (id = ANY (s.courses)) -> Bitmap Index Scan on course_pk (cost=0.00..9.58 rows=10 width=0) (actual time=0.005..0.005 rows=2 loops=4) Index Cond: (id = ANY (s.courses)) SubPlan 2 -> Bitmap Heap Scan on course course_1 (cost=9.59..20.24 rows=10 width=32) (actual time=0.005..0.005 rows=2 loops=4) Recheck Cond: (id = ANY (s.courses)) -> Bitmap Index Scan on course_pk (cost=0.00..9.58 rows=10 width=0) (actual time=0.002..0.002 rows=2 loops=4) Index Cond: (id = ANY (s.courses)) Total runtime: 0.168 ms (15 rows)
student表与course_info视图关联:
EXPLAIN ANALYZE SELECT s.id sid, s.name sname, s.courses, ci.cname,ci.ce_name FROM student s LEFT JOIN course_info ci ON s.courses = ci.courses ORDER BY s.id;
执行计划运行结果如下:
QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------------- Sort (cost=40608.35..40610.35 rows=800 width=136) (actual time=0.076..0.076 rows=4 loops=1) Sort Key: s.id Sort Method: quicksort Memory: 26kB -> Hash Right Join (cost=32440.22..40569.78 rows=800 width=136) (actual time=0.066..0.071 rows=4 loops=1) Hash Cond: (s_1.courses = s.courses) -> HashAggregate (cost=32412.22..40511.28 rows=200 width=32) (actual time=0.047..0.047 rows=4 loops=1) -> Seq Scan on student s_1 (cost=0.00..32406.22 rows=800 width=32) (actual time=0.025..0.043 rows=4 loops=1) SubPlan 1 -> Bitmap Heap Scan on course (cost=9.59..20.24 rows=10 width=32) (actual time=0.005..0.005 rows=2 loops=4) Recheck Cond: (id = ANY (s_1.courses)) -> Bitmap Index Scan on course_pk (cost=0.00..9.58 rows=10 width=0) (actual time=0.002..0.002 rows=2 loops=4) Index Cond: (id = ANY (s_1.courses)) SubPlan 2 -> Bitmap Heap Scan on course course_1 (cost=9.59..20.24 rows=10 width=32) (actual time=0.002..0.002 rows=2 loops=4) Recheck Cond: (id = ANY (s_1.courses)) -> Bitmap Index Scan on course_pk (cost=0.00..9.58 rows=10 width=0) (actual time=0.001..0.001 rows=2 loops=4) Index Cond: (id = ANY (s_1.courses)) -> Hash (cost=18.00..18.00 rows=800 width=72) (actual time=0.008..0.008 rows=4 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 1kB -> Seq Scan on student s (cost=0.00..18.00 rows=800 width=72) (actual time=0.003..0.004 rows=4 loops=1) Total runtime: 0.116 ms
我们可以看到,student表直接与course表关联查询,执行需要0.168 ms,与course_info视图进行关联查询,执行需要0.116 ms。对于关联信息越多的情况,效率提升越明显。
相关文章推荐
- golang自定义数据类型查询与插入postgresql中point数据
- golang自己定义数据类型查询与插入postgresql中point数据
- 表格式改为orc之后,对于array类型的数据查询结果不正确 问题排查和解决方案
- postgresql 数据支持 jsonb/json中 array或int 类型进行的交集比较
- PostgreSQL JSON ARRAY 数据类型
- SQL查询一列数据,结果为用特殊符号分割的一行数据
- PostgreSQL 与 SQL Server 的数据类型映射
- VC 常用数据类型总结
- Gentle.Net学习笔记二:常用查询数据的方法总结
- 查询某一个表的字段和数据类型
- ASP中如何查询日期类型的数据
- 关于对日期类型的数据进行模糊查询的问题
- Oracle数据库应用中几种基本数据引用关系中的特殊查询
- [Python]Python/PHP如何查询sql server中NTEXT类型数据
- 发布NBearLite v1.0.0: 提供强类型查询语法的非ORM数据访问组件 [8/2 更新至v1.0.0.9 beta - 修复NBearLite参考手册某些操作系统打开错误的问题]
- oracle日期类型数据查询解决例子
- VC 常用数据类型总结
- 对论坛中有关数据类型转换的总结
- 发布NBearLite v1.0.0: 提供强类型查询语法的非ORM数据访问组件 [8/2 更新至v1.0.0.9 beta - 修复NBearLite参考手册某些操作系统打开错误的问题]
- 如何查询日期类型的数据?