1.SQL基础
1.1 DDL
创建数据库
CREATE DATABASE db_name [[WITH] OWNER [=] user_name];
- 创建者自动成为新DB的owner
- 用户需要有CREATEDB权限(或者superuser)
删除数据库
DROP DATABASE [IF EXISTS] db_name;
- 只有该数据库的superuser或者该db的owner才能删除该数据库
- 删除数据库会移除其中包括的所有对象
- 不能在与目标数据库连接时执行DROP命令,但可以来连接到其他任意数据库
创建数据表
CREATE TABLE [IF EXISTS]
[schema_name.]table_name
([{column_name column_type [column_constraints, [...]]| table_contraints[, ...]
}]);
- 在创建表时,如果不存在同名表且语义正确,表创建都会返回成功
- 如果存在同名表:如果比指定IF NOT EXISTS选项,则返回异常;如果指定IF NOT EXISTS 选项,Holo会打印提示信息,跳过表创建步骤,返回成功
删除表
DROP TABLE [IF EXISTS] table_name [, ...];
- DROP TABLE支持一次DROP多个表
- 如果指定IF EXISTS,无论表存在与否,都会返回成功
- 如果不指定IF EXISTS 选项而表不存在,则返回异常:ERROR:table “xxx” does not exist.
修改表
仅支持重命名表(RENAME TABLE)和增加列(ADD CPLUMN)。对于外部表(foreign table)没有限制
-- 重命名表
ALTER TABLE table_name RENAME to new_table_name;-- 增加列
ALTER TABLE IF EXISTS table_name ADD COLUMN new_column_name data_type;
增加注释
Holo支持给表,外表,列等增加注释的功能
-- 给表增加注释
COMMENT ON TABLE table_name IS 'my comments on table table_name';-- 给列增加注释
COMMENT ON COLUMN table_name.col1 IS 'This my first col1';-- 给外部表增加注释
COMMENT ON FOREIGN TABLE foreign_table IS 'comment on my foreign table';
模式(SCHEMA)
- 一个数据库可以包含多个schema
- 多个用户使用一个数据库不会互相干扰,也便于管理
- 每个DB有一个默认的public schema
- Holo支持create schema、alter schema rename 暂时不支持drop schema
-- 查看当前schema
SELECT current_schema();-- 创建新的schema
CREATE SCHEMA my_schema;-- 跨schema建表
CREATE TABLE my_schema.mytest (name text, id int, age int);-- 原schema下的表将全部转到新schema下
ALTER SCHEMA oldschema rename to newschema;
分区表
PostgreSQL分区表用于将一张大表分成同构的若干张子表,利于加速查询、方便管理
-- 创建分区表
CREATE TABLE [IF NOT EXISTS] [schema_name.]table_name PARTITION OF parent_table FOR VALUES IN (string_literal);-- 分离目标表的指定分区
ALTER TABLE [IF EXISTS] table_name DETACH PARTITION partition_name;-- 删除分区表
DROP TABLE table_name;
外部表
指不存储于Hologres中的表。Hologres与大数据生态无缝打通,可对外部表直接加速查询,也可以将外部表的数据导入到Hologres中进行数据处理
目前Holo只支持MaxCompute中的表作为外部表
-- 新建外部表
CREATE FOREIGN TABLE src_pt_odps(key text)
server odps_server options(project_name 'odps_project', table_name 'test');-- 删除外部表
DROP FOREIGN TABLE [IF EXISTS] table_name [, ...]
[ CASCADE | RESTRICT];-- 查看外部表
SELECT * FROM table_name;
** CREATE CAST 用于定义数据类型之间的转换**
CREATE CAST(source_type AS target_type)WITH INOUT[ AS ASSIGNMENT | AS IMPLICIT]注:
source_type:该转换的源数据类型
targer_type:该转换的目标数据类型示例:创建数据类型之间的转换CREATE CAST (text AS integer) WITH INOUT AS IMPLICIT;
** DROP CAST语句用于删除已定义的数据类型转换
DROP CAST [IF EXISTS] (source_type AS targer_type)示例:
DROP CAST IF EXISTS (text AS timestamptz);
DROP CAST IF EXISTS (text AS integer);
创建视图
CREATE [TEMP | TEMPORARY] VIEW
view_name AS
SELECT column1, column2 ...
FROM table_name
WHERE [condition];-- 创建内部表视图
create view view1 as select * from t1_foreign;-- 创建内部表及外部表的联合视图
create view view2 as select * from t2_holo
union all
select * from t1_foreign;
删除视图
DROP VIEW <view_name>;
1.2 DML
插入
INSERT INTO table[(column [,...])] VALUES ({expression} [,...]) [, ...] | query在Hologres中,INSERT支持两种形式
1.插入确定的value
INSERT INTO rh_holo2 (cate_id, cate_name) VALUES
(3, 't1'),
(3, 'f1'),
(3, 'trxxue'),
(3, 'x'),
(4, 'sajojsaio');2.插入select的结果
INSERT INTO test2
SELECT * FROM test1;
DELETE:对表指定列的行数据进行删除
DELETE FROM table_name [*]
[ [AS] alias] [WHERE condition]alias:别名,目标表的替代名称
condition:删除的条件用法举例:
DELETE FROM delete_test AS dt WHERE dt.a = 10;
DELETE FROM delete_test AS dt WHERE dt.b is null;
DELETE FROM delete+test AS dt WHERE dt.b = "";
UPDATE:对表指定列的行数据进行更新
UPDATE table [*] [ [AS] alias]
SET column = {expression}
[ FROM from_list] [WHERE condition]alias:别名,目标表的代称
expression:表达式
condition:更新条件举例:
UPDATE update_test set b = b + 10 where a = 'b1';UPDATE update_test set c = 'new_' || a, d = null
where b = 20;UPDATE update_test set (b,c,d) = (1,"test_c","d");
SELECT查询语法
[WITH with_query [, ...]]
SELECT [ALL | DISTINCT [ ON (expression [, ...])]]
* | expression [[AS] output_name] [, ...]
[FROM from_item [, ...]]
[WHERE condition]
[GROUP BY grouping_element [, ...]]
[HAVING condition [, ...]]
[{UNION | INTERSECT | EXCEPT} [ALL] SELECT]
[ORDER BY expression [ASC | DESC | USING operator] [, ...]]
[LIMIT {count | ALL}]DISTINCT:取出重复行,只保留一行
FROM:为SELECT指定一个或更多源表
WHERE:展示condition指定的内容
GROUP BY:按照指定的表达式分组
HAVING:过滤
UNION:SELECT语句所返回的行的并集
INTERSECT:select语句返回的行的交集
EXCEPT:计算位于左SELECT语句的结果中但不在右SELECT语句结果中的行集合
ORDER BY:按照指定的表达式排序
LIMIT:count指定要返回的最大行数示例:
select * from sale_detail where shop_name like 'hang%';
从sale_detail表中查询所有带hang的店铺select region from sale_detail group by region;
从sale_detail表中查询region信息并以region进行分组select * from sale_detail order by region limit 100;
从sale_detail表中查询region信息并以region排序数据100行
UNION并集
求两个数据集的并集。即,将两个数据集合并成一个数据集
未去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
UNION ALL
SELECT * FROM VALUES (1, 2), (3, 4) t(a, b);去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
UNION
SELECT * FROM VALUES (1, 2), (3, 4) t(a, b);
INTERSECT交集
求两个数据集的交集。即,数据两个数据集均包含的记录
未去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
INTERSECT ALL
SELECT * FROM VALUES (1, 2), (1, 2), (7, 8) t(a, b);去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
INTERSECT
SELECT * FROM VALUES (1, 2), (1, 2), (7, 8) t(a, b);
EXCEPT补集
求第二个数据集在第一个数据集中的补集。即,输出第一个数据集包含而第二个数据集不包含的记录
未去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
EXCEPT ALL
SELECT * FROM VALUES (1, 2), (1, 2), (7, 8) t(a, b);去重:
SELECT * FROM VALUES (1, 2), (1, 2), (3, 4) t(a, b)
EXCEPT
SELECT * FROM VALUES (1, 2), (1, 2), (7, 8) t(a, b);
INSERT ON CONFLICT语句用于在指定列插入某行数据时,如果主键存在重复的行数据,则对该数据执行更新或跳过操作
应用场景:适用于SQL方式导入数据的场景
create table conflict_2(a int not null primary key,b int,c int
);insert into conflict_2 values(1,5,6);insert into conflict_1 select * from conflict_2 on conflict(a) do update set b = excluded.b; //主键相同时,将表conflict_2的列数据更新到conflict_1中insert into conflict_1 values(2,7,8) on conflict(a) do update set b = excluded.b, c = excluded,c
where conflict_1.c = 4; //主键值相同时,将表conflict_2的某一行数据全部插入至表conflict_1中insert into conflict_1 select * from conflict_2 on conflict(a) do nothing; //主键相同时,跳过表conflict_2的数据insert into conflict_1 select * from conflict_2 on conflict do nothing; //do nothing不指定冲突列时,默认冲突列为主键
TRUNCATE语句用于清空目标表
使用限制:
- Hologres支持Sequence,但目前仅支持CONTINUE IDENTITY,不支持RESTART IDENTITY
- Hologres支持对普通表、分区父表及分区子表执行TRUNCATE语句
- Hologres不支持对外部表执行TRUNCATE语句
TRUNCATE [TABLE] name [, ...] [CONTINUE IDENTITY | RESTART IDENTITY]# 默认为CONTINUE IDENTITY
2.SQL高阶
2.1 存储属性设置
- Hologres目前通过set_table_property procedure来指定表的额外物理存储属性,合理设置table property对于查询的性能影响极大
- set_table_property的调用需要与create table在同一事务中执行
- set_table_property对于同一个key不能重复调用
call set_table_property('table_name', 'orientation', '[column | row]');
call set_table_property('table_name', 'clustering_key', '[columnName{: [desc | asc]} [, ...]]');
call set_table_property('table_name', 'segment_key', '[columnName [, ...]]');
call set_table_property('table_name', 'bitmap_columns', '[columnName [, ...]]');
call set_table_property('table_name', 'dictionary_encoding_columns', '[columnName [,...]]');
call set_table_property('table_name', 'time_to_live_in_seconds', '<non_negative_literal>');
call set_table_property('table_name', 'distribution_key', '[columnName [, ...]]');
2.2 存储类型设置
- Hologres目前支持按行存储和按列存储两种存储类型,通过orientation来指定
- 按行存储对于高QPS的基于primary key的点查询性能较好,例如where pk = abc,其余场景应该选用按列存
# 按行存
begin;
create table tb1 (a int not null, b text not null, primary key(a));
call set_table_property("tb1", "orientation", "row");
commit;# 按列存
begin;
create table tb1 (a int not null, b text not null, primary key(a));
call set_table_property("tb1", "orientation", "column");
commit;
2.3 聚簇键设置
- clustering_key 指定一列作为聚簇索引,Hologres在指定的列上将建立聚簇索引。Hologres会在聚簇索引上对数据进行排序,建立聚簇索引能够加速用户在索引列上的range和filter查询
- 数据类型为float/double的列,不能设置为clustering_key
- 每个表只能有最多一个聚簇索引
begin;
create table tb1 (a int not null, b text not null);
call set_table_property('tb1', 'clustering_key', 'a');
commit;
2.4 分段键设置
- segment_key指定一些列作为分段键,当查询条件包含分段列时,查询可以通过segment_key快速找到相应数据对应的存储位置,segment_key要求按照数据输入自增
- 一般只有时间类型的字段(timestamptz)适合设置为segment_key,其他场景基本不需要设置
- 只有列存表支持分段键
begin;
create table tb1 (a int not null, ts timestamp not null);
call set_table_property('tb1', 'segment_key', 'ts');
commit;
2.5 比特编码列设置
- bitmap_columns指定比特编码列,Hologres在这些列上构建比特编码。bitmap可以对segment内部的数据进行快速过滤,所以建议用户把filter条件的数据建成比特编码
- 默认所有text列都会被隐式地设置到bitmap_columns中
- 只有列存表支持比特编码列
begin;
create table tb1 (a int not null, b text not null);
call set_table_property('tb1', 'bitmap_columns', 'a');
commit;
2.6 字典编码列设置
- dictionary_encoding_columns指定字典编码列,Hologres为指定列的值构建字典映射,字典编码可以将字符串的比较转成数字的比较,加速group by查询,建议用户将group by的字段都建成dictionary_encoding_columns
- 默认所有text列都会被隐式地设置到dictionary_encoding_columns中
- 不建议将基数高的列建为dictionary_encoding_columns,会导致查询性能变差
- 只有列存表支持字典编码列
begin;
create table tb1 (a int not null, b text not null);
call set_table_property('tb1', 'dictionary_encoding_columns', 'b');
commit;
2.7 分布键设置
- Hologres中,数据库表默认为随机分布形式。数据将被随机分配到各个shard上,如果用户制定了分布列,数据将按照指定列,将数据shuffle到各个shard,同样的数据肯定会在同样的shard中,当用户以分布列左过滤条件时,Hologres可以直接筛选出数据相关的shard进行扫描。当用户以分布列做join条件时,Hologres不需要再次将数据shuffle到其他计算节点,直接在本节点join数据即可,可大大提高执行效率。同时如果用户group by的key的时分布列也可以减少一次数据shuffle
- 有pk的数表,默认时pk,可以指定pk字段的子集,不能随意指定
- 用户可以用过shard_count来指定表的shard数,如果不指定每个数据库都有一个默认的shard数。一旦用户指定了一个表的shard数,其他的表如果想要和这个表做local join必须指定colcate with这个表
begin;
create table tb1 (a int, b int, c int);
call set_table_property('tb1', 'distribution_key', 'a');
commit;begin;
create table tb2 (a int, b int, c int);
call set_table_property('tb1', 'distribution_key', 'b');
commit;select count(1) from tb1 join tb2 on tb1.a = tb2.b; -- 将分布列设置为join key
2.8 数据生命周期管理
- time_to_live_in_seconds 指定了表数据的生存时间,单位为秒,必须非负数字类型
- 表数据的TTL并不是精确的时间,当超过设置的TTL后,系统会在某一个时间自动删除表数据,所以业务逻辑不能强依赖TTL
begin;
create table tb1 (a int not null, b text not null);
call set_table_property('tb1', 'time_to_live_in_seconds', '3.1415926');
commit;
2.9 性能调优
用过explain查看执行计划
执行analyze,生成统计信息