介绍和使用大埔卫生院
一、TPCH相关知识
1.tpch简介
TPCH是国际事务处理性能委员会(TPC,Transaction Processing Performance Council)于 1994 年指定的标准,是一款面向商品零售业务的决策支持系统测试基准,TPCH包含8张表,22个查询,遵循SQL92。
tpc事务处理性能委员会( Transaction ProcessingPerformance Council )
tpc-h 模拟决策支持系统中的数据库操作,测试数据库系统复杂查询的响应时间,以每小时执行的查询数(TPC-H QphH@Siz)作为度量指标.
tpc-h规范:
Query: 22条sql
Modify: RF1, RF2
3个测试:数据装载、顺序执行一次query+modify、模拟生产
模拟生产:在22个查询执行的同时,还有一对更新操作RF1 和RF2 并发地执行,RF1向Order 表和Lineitem 表中插入原行数的0.1%的新行,模拟新销售业务的数据加入到数据库中;RF2 从Order 表和Lineitem表中删除等量与RF1 增加的数据,模拟旧的销售数据被淘汰
2.tpch关系图
TPC-H包括8张表(表上有些约束等需要满足,参见TPC-H规范),如下:
PART:表示零件的信息,如表4-1所示。
SUPPLIER:表示供货商的信息,如表4-2所示。
PARTSUPP:表示供货商的零件的信息,如表4-3所示。
CUSTOMER:表示消费者的信息,如表4-4所示。
ORDERS:表示订单的信息,如表4-5所示。
LINEITEM:表示在线商品的信息,如表4-6所示。
NATION:表示国家的信息,如表4-7所示。
REGION:表示地区的信息,如表4-8所示。
这8张表之间的关系,如图4-1所示或图4-2所示。
3.行存与列存
行存
https://www.cnblogs.com/gc65/p/11011885.html
TOAST表,这种存储方式叫行外存储。一般当一条记录压缩后的大小大于TOAST_TUPLE_THRESHOLD(通常是page_size/4即2kB)这个值时,会存储到TOAST表。
create table t5(id int,name text);
select relname,relfilenode,reltoastrelid from pg_class where relname='t5';
relname | relfilenode | reltoastrelid
---------+-------------+---------------
t5 | 42069 | 42072
select * from pg_toast.pg_toast_42069;
chunk_id | chunk_seq | chunk_data
----------+-----------+------------
PLAIN:避免压缩和行外存储。只有那些不需要TOAST策略就能存放的数据类型允许选择(例如int类型),而对于text这类要求存储长度超过页大小的类型,是不允许采用此策略的
EXTENDED:允许压缩和行外存储。一般会先压缩,如果还是太大,就会行外存储(默认)
EXTERNAL:允许行外存储,但不许压缩。类似字符串这种会对数据的一部分进行操作的字段,采用此策略可能获得更高的性能,因为不需要读取出整行数据再解压。
MAIN:允许压缩,但不许行外存储。不过实际上,为了保证过大数据的存储,行外存储在其它方式(例如压缩)都无法满足需求的情况下,作为最后手段还是会被启动。因此理解为:尽量不使用行外存储更贴切。一般只有在变长的字段上且存储模式不是PLAIN时才能启用TOAST。
#列存
列存表以CU为单位,默认60000一个CU,自带min/max稀疏索引。
列的联系:col_id + cuid + offset
set search_path=cstore;
\d
Schema | Name | Type | Owner | Storage
--------+-----------------+-------+----------+-----------------------
cstore | pg_cudesc_41964 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_41977 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_41990 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_42003 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_42016 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_42029 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_42042 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_42055 | table | vastbase | {internal_mask=33031}
cstore | pg_delta_41964 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_41977 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_41990 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_42003 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_42016 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_42029 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_42042 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_42055 | table | vastbase | {internal_mask=32768}
\d from pg_cudesc_42055;
Column | Type | Modifiers | Storage | Stats target | Description
------------+---------+-----------+----------+--------------+-------------
col_id | integer | | plain | |
cu_id | oid | | plain | |
min | text | | extended | |
max | text | | extended | |
row_count | integer | | plain | |
cu_mode | integer | | plain | |
size | bigint | | plain | |
cu_pointer | text | | extended | |
magic | integer | | plain | |
extra | text | | extended | |
--局部聚簇约束(Partial Cluster Key)
列存下的一种技术。这种技术可以通过min/max稀疏索引较快的实现基表扫描的filter过滤。Partial Cluster Key可以指定多列,但是一般不建议超过2列。 简单讲就是按照clusterkey进行有序存储。
Partial Cluster Key的选取原则:
受基表中的简单表达式约束。这种约束一般形如col op const,其中col为列名,op为操作符 =、>、>=、<=、<,const为常量值。
尽量采用选择度比较高(过滤掉更多数据)的简单表达式中的列。
尽量把选择度比较低的约束col放在Partial Cluster Key中的前面。
尽量把枚举类型的列放在Partial Cluster Key中的前面。
--psort索引
PSort CU临近有序,查询交集尽量减少,提升查询的效率。
列数据min/max之间的数据比较离散时,可以建立psort索引
--btree索引
b树索引和行存基本类似,不同之处在于行存使用ctid,列存使用cuid(n)+偏移量
--delta表:
列存表附带的行存表,在做小批量数据插入时候,为了提升查询性能,减少cu空间消耗
开启delta表:ALTER TABLE table_name SET (enable_delta=TRUE);
关闭delta表:ALTER TABLE table_name SET (enable_delta=FALSE);
GaussDB提供两种合并操作:自动的auto-deltaMerge和手动的deltaMerge。auto-deltaMerge会将默认60000行以上的数据合并到列存储,而手动deltaMerge会将全部数据从Delta存储合并至列存储。但手动deltaMerge依赖高级别的锁,需谨慎使用
--列存相关参数
shared_buffers
列存cudesc和delta信息存储需要
cstore_buffers
列存所使用的共享缓冲区的大小,默认值:32768KB。
max_loaded_cudesc
设置列存表在做扫描时,缓存cudesc信息的个数。增大设置会提高查询性能,但也会增加内存占用,特别是当列存表的列非常多时。
cstore_prefetch_quantity
描述列存储使用ADIO预取IO量的大小
cstore_backwrite_quantity
描述列存储使用ADIO写入IO量的大小
cstore_backwrite_max_threshold
描述列存储使用ADIO写入数据库可缓存最大的IO量
fast_extend_file_size
描述列存储使用ADIO预扩展磁盘的大小
psort_work_mem
设置列存表在进行局部排序中,在开始写入临时磁盘文件之前使用的内存大小。带partial cluster key的表、带索引的表插入、创建表索引、删除表和更新表都会用到
partition_mem_batch
指定缓存个数,为了优化对列存分区表的批量插入,在批量插入过程中会对数据进行缓存后再批量写盘。默认值:256 。
partition_max_cache_size
指定数据缓存区大小,为了优化对列存分区表的批量插入,在批量插入过程中会对数据进行缓存后再批量写盘。默认值:2GB。
enable_delta_store
为了增强列存单条数据导入的性能和解决磁盘冗余问题,是否需要开启列存delta表功能,与参数DELTAROW_THRESHOLD 配合使用。默认值:off。
4.并行与连接
并行:
query_dop本质
并行查询不是指多个会话的并发,而是服务器为单个查询开启至少2n+1个并行线程,其中n个线程用于生产数据,n个线程用于消费数据,1个线程用于协调汇总,最后反馈给客户端。因此并行度越大,带来的资源消耗则是成倍增长,可能会导致主机资源耗尽。
select id from t order by id;
生产者thred1: 1,3,5 -> 消费者thred3: 1,3,5 -> 协调线程:1,2,3,4,5,6
生产者thred2: 4,6,2 -> 消费者thred4: 2,4,6
1.生产者划分n个数据区。提交给消费者后就可以做其他事了
2.消费者处理数据,必须要等待所有消费线程处理完成
3.协调线程汇总消费者数据,返回给客户端
#例外
1.数据倾斜:数据倾斜会导致生产者数据不均匀,消费者并行效果差。
2.资源竞争:高并发场景下,开启并行,会导致各查询之间严重的资源竞争问题
3.索引扫描:不支持并行
表的连接:
nestloop_join: 驱动表较小,且内表连接字段必须有索引
hash_join: 两表数据量相差很大。小表连接字段建立散列表,大表去探测散列表
merge_join: 没有索引,数据源已经排序。
5.执行计划
explain [ ( option [, ...] ) ] statement
ANALYZE [ boolean ] |
ANALYSE [ boolean ] |
VERBOSE [ boolean ] | 默认为false 参数可以显示执行集合更多信息
COSTS [ boolean ] | 默认为TRUE
CPU [ boolean ] |
DETAIL [ boolean ] |
NODES [ boolean ] |
NUM_NODES [ boolean ] |
BUFFERS [ boolean ] | 缺省为FALSE
TIMING [ boolean ] | 缺省为TRUE
PLAN [ boolean ] |
FORMAT { TEXT | XML | JSON | YAML }
explain + statement
explain analyze + statement
explain (ANALYZE true,buffers true) + statement
1.costs总代价最大的子句
2.预估rows与实际rows相差是否过大
3.使用buffers查看是否使用了磁盘
4.为什么没有走索引扫描,索引建立不合适?表较小?可能结果集比较大?(一般结果集超过total*40%就可能走全表了,感兴趣可以研究costs计算方式或者直接强制走索引对比)
5.多表连接如何选择,优化器正常会走合适的连接方式,也可以强制关闭其他连接开关。
6.。。。
二、安装TPCH工具
1.安装工具下载:
1).TPC-H工具下载网站:http://www.tpc.org/tpch/
2)链接:https://pan.baidu.com/s/1VuB-reZ_1EiWT8cj_wrGhw
提取码:rqgg
2.解压安装包
unzip tpc-h-tool-3.0.0.zip -d /home/tpcc/
3.编辑makefile.suite
cd /home/tpcc/TPC-H_Tools_v3.0.0/dbgen
vi makefile.suite
CC = gcc
DATABASE= POSTGRESQL
MACHINE = LINUX
WORKLOAD = TPCH
4.编辑tpcd.h
vi tpcd.h
#ifdef POSTGRESQL
#define GEN_QUERY_PLAN "EXPLAIN PLAN"
#define START_TRAN "SET TRANSACTION"
#define END_TRAN "COMMIT;"
#define SET_OUTPUT ""
#define SET_ROWCOUNT "LIMIT %d\n"
#define SET_DBASE ""
#endif
5.执行编译安装
make -f makefile.suite
6.生成裸数据
dbgen参数详解
TPCH是国际事务处理性能委员会(TPC,Transaction Processing Performance Council)于 1994 年指定的标准,是一款面向商品零售业务的决策支持系统测试基准,TPCH包含8张表,22个查询,遵循SQL92。
tpc事务处理性能委员会( Transaction ProcessingPerformance Council )
tpc-h 模拟决策支持系统中的数据库操作,测试数据库系统复杂查询的响应时间,以每小时执行的查询数(TPC-H QphH@Siz)作为度量指标.
tpc-h规范:
Query: 22条sql
Modify: RF1, RF2
3个测试:数据装载、顺序执行一次query+modify、模拟生产
模拟生产:在22个查询执行的同时,还有一对更新操作RF1 和RF2 并发地执行,RF1向Order 表和Lineitem 表中插入原行数的0.1%的新行,模拟新销售业务的数据加入到数据库中;RF2 从Order 表和Lineitem表中删除等量与RF1 增加的数据,模拟旧的销售数据被淘汰
TPC-H包括8张表(表上有些约束等需要满足,参见TPC-H规范),如下:
PART:表示零件的信息,如表4-1所示。
SUPPLIER:表示供货商的信息,如表4-2所示。
PARTSUPP:表示供货商的零件的信息,如表4-3所示。
CUSTOMER:表示消费者的信息,如表4-4所示。
ORDERS:表示订单的信息,如表4-5所示。
LINEITEM:表示在线商品的信息,如表4-6所示。
NATION:表示国家的信息,如表4-7所示。
REGION:表示地区的信息,如表4-8所示。
这8张表之间的关系,如图4-1所示或图4-2所示。
https://www.cnblogs.com/gc65/p/11011885.html
TOAST表,这种存储方式叫行外存储。一般当一条记录压缩后的大小大于TOAST_TUPLE_THRESHOLD(通常是page_size/4即2kB)这个值时,会存储到TOAST表。
create table t5(id int,name text);
select relname,relfilenode,reltoastrelid from pg_class where relname='t5';
relname | relfilenode | reltoastrelid
---------+-------------+---------------
t5 | 42069 | 42072
select * from pg_toast.pg_toast_42069;
chunk_id | chunk_seq | chunk_data
----------+-----------+------------
PLAIN:避免压缩和行外存储。只有那些不需要TOAST策略就能存放的数据类型允许选择(例如int类型),而对于text这类要求存储长度超过页大小的类型,是不允许采用此策略的
EXTENDED:允许压缩和行外存储。一般会先压缩,如果还是太大,就会行外存储(默认)
EXTERNAL:允许行外存储,但不许压缩。类似字符串这种会对数据的一部分进行操作的字段,采用此策略可能获得更高的性能,因为不需要读取出整行数据再解压。
MAIN:允许压缩,但不许行外存储。不过实际上,为了保证过大数据的存储,行外存储在其它方式(例如压缩)都无法满足需求的情况下,作为最后手段还是会被启动。因此理解为:尽量不使用行外存储更贴切。一般只有在变长的字段上且存储模式不是PLAIN时才能启用TOAST。
#列存
列存表以CU为单位,默认60000一个CU,自带min/max稀疏索引。
列的联系:col_id + cuid + offset
set search_path=cstore;
\d
Schema | Name | Type | Owner | Storage
--------+-----------------+-------+----------+-----------------------
cstore | pg_cudesc_41964 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_41977 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_41990 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_42003 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_42016 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_42029 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_42042 | table | vastbase | {internal_mask=33031}
cstore | pg_cudesc_42055 | table | vastbase | {internal_mask=33031}
cstore | pg_delta_41964 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_41977 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_41990 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_42003 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_42016 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_42029 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_42042 | table | vastbase | {internal_mask=32768}
cstore | pg_delta_42055 | table | vastbase | {internal_mask=32768}
\d from pg_cudesc_42055;
Column | Type | Modifiers | Storage | Stats target | Description
------------+---------+-----------+----------+--------------+-------------
col_id | integer | | plain | |
cu_id | oid | | plain | |
min | text | | extended | |
max | text | | extended | |
row_count | integer | | plain | |
cu_mode | integer | | plain | |
size | bigint | | plain | |
cu_pointer | text | | extended | |
magic | integer | | plain | |
extra | text | | extended | |
--局部聚簇约束(Partial Cluster Key)
列存下的一种技术。这种技术可以通过min/max稀疏索引较快的实现基表扫描的filter过滤。Partial Cluster Key可以指定多列,但是一般不建议超过2列。 简单讲就是按照clusterkey进行有序存储。
Partial Cluster Key的选取原则:
受基表中的简单表达式约束。这种约束一般形如col op const,其中col为列名,op为操作符 =、>、>=、<=、<,const为常量值。
尽量采用选择度比较高(过滤掉更多数据)的简单表达式中的列。
尽量把选择度比较低的约束col放在Partial Cluster Key中的前面。
尽量把枚举类型的列放在Partial Cluster Key中的前面。
--psort索引
PSort CU临近有序,查询交集尽量减少,提升查询的效率。
列数据min/max之间的数据比较离散时,可以建立psort索引
--btree索引
b树索引和行存基本类似,不同之处在于行存使用ctid,列存使用cuid(n)+偏移量
--delta表:
列存表附带的行存表,在做小批量数据插入时候,为了提升查询性能,减少cu空间消耗
开启delta表:ALTER TABLE table_name SET (enable_delta=TRUE);
关闭delta表:ALTER TABLE table_name SET (enable_delta=FALSE);
GaussDB提供两种合并操作:自动的auto-deltaMerge和手动的deltaMerge。auto-deltaMerge会将默认60000行以上的数据合并到列存储,而手动deltaMerge会将全部数据从Delta存储合并至列存储。但手动deltaMerge依赖高级别的锁,需谨慎使用
--列存相关参数
shared_buffers
列存cudesc和delta信息存储需要
cstore_buffers
列存所使用的共享缓冲区的大小,默认值:32768KB。
max_loaded_cudesc
设置列存表在做扫描时,缓存cudesc信息的个数。增大设置会提高查询性能,但也会增加内存占用,特别是当列存表的列非常多时。
cstore_prefetch_quantity
描述列存储使用ADIO预取IO量的大小
cstore_backwrite_quantity
描述列存储使用ADIO写入IO量的大小
cstore_backwrite_max_threshold
描述列存储使用ADIO写入数据库可缓存最大的IO量
fast_extend_file_size
描述列存储使用ADIO预扩展磁盘的大小
psort_work_mem
设置列存表在进行局部排序中,在开始写入临时磁盘文件之前使用的内存大小。带partial cluster key的表、带索引的表插入、创建表索引、删除表和更新表都会用到
partition_mem_batch
指定缓存个数,为了优化对列存分区表的批量插入,在批量插入过程中会对数据进行缓存后再批量写盘。默认值:256 。
partition_max_cache_size
指定数据缓存区大小,为了优化对列存分区表的批量插入,在批量插入过程中会对数据进行缓存后再批量写盘。默认值:2GB。
enable_delta_store
为了增强列存单条数据导入的性能和解决磁盘冗余问题,是否需要开启列存delta表功能,与参数DELTAROW_THRESHOLD 配合使用。默认值:off。
并行:
query_dop本质
并行查询不是指多个会话的并发,而是服务器为单个查询开启至少2n+1个并行线程,其中n个线程用于生产数据,n个线程用于消费数据,1个线程用于协调汇总,最后反馈给客户端。因此并行度越大,带来的资源消耗则是成倍增长,可能会导致主机资源耗尽。
select id from t order by id;
生产者thred1: 1,3,5 -> 消费者thred3: 1,3,5 -> 协调线程:1,2,3,4,5,6
生产者thred2: 4,6,2 -> 消费者thred4: 2,4,6
1.生产者划分n个数据区。提交给消费者后就可以做其他事了
2.消费者处理数据,必须要等待所有消费线程处理完成
3.协调线程汇总消费者数据,返回给客户端
#例外
1.数据倾斜:数据倾斜会导致生产者数据不均匀,消费者并行效果差。
2.资源竞争:高并发场景下,开启并行,会导致各查询之间严重的资源竞争问题
3.索引扫描:不支持并行
表的连接:
nestloop_join: 驱动表较小,且内表连接字段必须有索引
hash_join: 两表数据量相差很大。小表连接字段建立散列表,大表去探测散列表
merge_join: 没有索引,数据源已经排序。
explain [ ( option [, ...] ) ] statement
ANALYZE [ boolean ] |
ANALYSE [ boolean ] |
VERBOSE [ boolean ] | 默认为false 参数可以显示执行集合更多信息
COSTS [ boolean ] | 默认为TRUE
CPU [ boolean ] |
DETAIL [ boolean ] |
NODES [ boolean ] |
NUM_NODES [ boolean ] |
BUFFERS [ boolean ] | 缺省为FALSE
TIMING [ boolean ] | 缺省为TRUE
PLAN [ boolean ] |
FORMAT { TEXT | XML | JSON | YAML }
explain + statement
explain analyze + statement
explain (ANALYZE true,buffers true) + statement
1.costs总代价最大的子句
2.预估rows与实际rows相差是否过大
3.使用buffers查看是否使用了磁盘
4.为什么没有走索引扫描,索引建立不合适?表较小?可能结果集比较大?(一般结果集超过total*40%就可能走全表了,感兴趣可以研究costs计算方式或者直接强制走索引对比)
5.多表连接如何选择,优化器正常会走合适的连接方式,也可以强制关闭其他连接开关。
6.。。。
1.安装工具下载:
1).TPC-H工具下载网站:http://www.tpc.org/tpch/
2)链接:https://pan.baidu.com/s/1VuB-reZ_1EiWT8cj_wrGhw
提取码:rqgg
2.解压安装包
unzip tpc-h-tool-3.0.0.zip -d /home/tpcc/
3.编辑makefile.suite
cd /home/tpcc/TPC-H_Tools_v3.0.0/dbgen
vi makefile.suite
CC = gcc
DATABASE= POSTGRESQL
MACHINE = LINUX
WORKLOAD = TPCH
4.编辑tpcd.h
vi tpcd.h
#ifdef POSTGRESQL
#define GEN_QUERY_PLAN "EXPLAIN PLAN"
#define START_TRAN "SET TRANSACTION"
#define END_TRAN "COMMIT;"
#define SET_OUTPUT ""
#define SET_ROWCOUNT "LIMIT %d\n"
#define SET_DBASE ""
#endif
5.执行编译安装
make -f makefile.suite
6.生成裸数据
dbgen参数详解
-v 详细信息
-s 表示生成G数据
-1 SF,Scale Factor ,数据库的比例因子。TPC-H标准规定,测试数据库的比例因子必须从下列固定值中选择:1,10,30,100,1000,3000,10000 (相当于1GB,10GB,30GB,100GB,1000GB,3000GB,10000GB)。数据库的大小缺省定义为1(例如:SF=1;近似于1GB)。
-S 切分数据
-f 覆盖之前的文件
更多参数可使用 ./dbgen -help 查看
./dbgen -s xxx ---这里的xxx表示想要生成的数据量(单位GB)
注:这里的-s 参数指定生成测试数据的仓库数,建议设置100以上,这里为了方便,选取较小的值,真实业务场景测试可设置1000以上。
生成的数据文件存放在/home/tpcc/TPC-H_Tools_v3.0.0/dbgen目录下,以tbl结尾,一共8个文件,对应的是8个表
7.创建TPCH相关表
详见行存/列存第2步创建数据表。
# 注意:dss.ddl 这个文件存储的是建表的语句
8.执行对应sql
将22条sql分别命名为1~22.sql文件,并将执行脚本与sql存放在同一目录,并在每个sql文件前加上 \timing on开启执行时间记录。
***脚本和sql文件属组必须是数据库安装用户,且具有创建文件权限。
22条sql文件及执行脚本获取地址:
链接:https://pan.baidu.com/s/1fi1nihHMMmsKYfeXyegbwA
提取码:zhzk
vi tpch_sql.sh
for i in `seq 1 22`
do
su - vastbase -c "vsql -d tpch -f ${i}.sql"
done
还可以将运行结果写入到日志中,日志将加载详细运行过程及运行时间,方便对sql运行结果进行分析。
for i in `seq 1 22`
do
su - vastbase -c "vsql -d tpch -f ${i}.sql >>${i}sql.log"
done
三、行存测试
1.创建database
create database tpch;
--create tablespace tpch location '/data/tpch';
--alter database tpch set tablespace tpch;
2. 创建数据表
CREATE TABLE NATION ( N_NATIONKEY INTEGER NOT NULL,
N_NAME CHAR(25) NOT NULL,
N_REGIONKEY INTEGER NOT NULL,
N_COMMENT VARCHAR(152),
N_NULL VARCHAR(10)
);
CREATE TABLE REGION ( R_REGIONKEY INTEGER NOT NULL,
R_NAME CHAR(25) NOT NULL,
R_COMMENT VARCHAR(152),
R_NULL VARCHAR(10)
);
CREATE TABLE PART ( P_PARTKEY INTEGER NOT NULL,
P_NAME VARCHAR(55) NOT NULL,
P_MFGR CHAR(25) NOT NULL,
P_BRAND CHAR(10) NOT NULL,
P_TYPE VARCHAR(25) NOT NULL,
P_SIZE INTEGER NOT NULL,
P_CONTAINER CHAR(10) NOT NULL,
P_RETAILPRICE DECIMAL(15,2) NOT NULL,
P_COMMENT VARCHAR(23) NOT NULL,
P_NULL VARCHAR(10)
);
CREATE TABLE SUPPLIER ( S_SUPPKEY INTEGER NOT NULL,
S_NAME CHAR(25) NOT NULL,
S_ADDRESS VARCHAR(40) NOT NULL,
S_NATIONKEY INTEGER NOT NULL,
S_PHONE CHAR(15) NOT NULL,
S_ACCTBAL DECIMAL(15,2) NOT NULL,
S_COMMENT VARCHAR(101) NOT NULL,
S_NULL VARCHAR(10)
);
CREATE TABLE PARTSUPP ( PS_PARTKEY INTEGER NOT NULL,
PS_SUPPKEY INTEGER NOT NULL,
PS_AVAILQTY INTEGER NOT NULL,
PS_SUPPLYCOST DECIMAL(15,2) NOT NULL,
PS_COMMENT VARCHAR(199) NOT NULL,
PS_NULL VARCHAR(10)
);
CREATE TABLE CUSTOMER ( C_CUSTKEY INTEGER NOT NULL,
C_NAME VARCHAR(25) NOT NULL,
C_ADDRESS VARCHAR(40) NOT NULL,
C_NATIONKEY INTEGER NOT NULL,
C_PHONE CHAR(15) NOT NULL,
C_ACCTBAL DECIMAL(15,2) NOT NULL,
C_MKTSEGMENT CHAR(10) NOT NULL,
C_COMMENT VARCHAR(117) NOT NULL,
C_NULL VARCHAR(10)
);
CREATE TABLE ORDERS ( O_ORDERKEY INTEGER NOT NULL,
O_CUSTKEY INTEGER NOT NULL,
O_ORDERSTATUS CHAR(1) NOT NULL,
O_TOTALPRICE DECIMAL(15,2) NOT NULL,
O_ORDERDATE DATE NOT NULL,
O_ORDERPRIORITY CHAR(15) NOT NULL,
O_CLERK CHAR(15) NOT NULL,
O_SHIPPRIORITY INTEGER NOT NULL,
O_COMMENT VARCHAR(79) NOT NULL,
O_NULL VARCHAR(10)
);
CREATE TABLE LINEITEM ( L_ORDERKEY INTEGER NOT NULL,
L_PARTKEY INTEGER NOT NULL,
L_SUPPKEY INTEGER NOT NULL,
L_LINENUMBER INTEGER NOT NULL,
L_QUANTITY DECIMAL(15,2) NOT NULL,
L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL,
L_DISCOUNT DECIMAL(15,2) NOT NULL,
L_TAX DECIMAL(15,2) NOT NULL,
L_RETURNFLAG CHAR(1) NOT NULL,
L_LINESTATUS CHAR(1) NOT NULL,
L_SHIPDATE DATE NOT NULL,
L_COMMITDATE DATE NOT NULL,
L_RECEIPTDATE DATE NOT NULL,
L_SHIPINSTRUCT CHAR(25) NOT NULL,
L_SHIPMODE CHAR(10) NOT NULL,
L_COMMENT VARCHAR(44) NOT NULL,
L_NULL VARCHAR(10)
);
3. 导入数据
copy customer from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/customer.tbl' DELIMITERS '|';
copy lineitem from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/lineitem.tbl' DELIMITERS '|';
copy nation from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/nation.tbl' DELIMITERS '|';
copy orders from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/orders.tbl' DELIMITERS '|';
copy partsupp from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/partsupp.tbl' DELIMITERS '|';
copy part from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/part.tbl' DELIMITERS '|';
copy region from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/region.tbl' DELIMITERS '|';
copy supplier from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/supplier.tbl' DELIMITERS '|';
3. 创建索引
ALTER TABLE REGION ADD PRIMARY KEY (R_REGIONKEY);
ALTER TABLE NATION ADD PRIMARY KEY (N_NATIONKEY);
ALTER TABLE PART ADD PRIMARY KEY (P_PARTKEY);
ALTER TABLE SUPPLIER ADD PRIMARY KEY (S_SUPPKEY);
ALTER TABLE PARTSUPP ADD PRIMARY KEY (PS_PARTKEY,PS_SUPPKEY);
ALTER TABLE CUSTOMER ADD PRIMARY KEY (C_CUSTKEY);
ALTER TABLE LINEITEM ADD PRIMARY KEY (L_ORDERKEY,L_LINENUMBER);
ALTER TABLE ORDERS ADD PRIMARY KEY (O_ORDERKEY);
ALTER TABLE PARTSUPP ADD FOREIGN KEY (PS_PARTKEY) REFERENCES PART(P_PARTKEY);
ALTER TABLE LINEITEM ADD FOREIGN KEY (L_ORDERKEY) REFERENCES ORDERS(O_ORDERKEY);
CREATE INDEX l_shipdate_idx ON LINEITEM(L_SHIPDATE);
vacuum ANALYZE ;
四、列存测试
1.创建测试表
CREATE TABLE NATION ( N_NATIONKEY INTEGER NOT NULL,
N_NAME CHAR(25) NOT NULL,
N_REGIONKEY INTEGER NOT NULL,
N_COMMENT VARCHAR(152),
N_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE REGION ( R_REGIONKEY INTEGER NOT NULL,
R_NAME CHAR(25) NOT NULL,
R_COMMENT VARCHAR(152),
R_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE PART ( P_PARTKEY INTEGER NOT NULL,
P_NAME VARCHAR(55) NOT NULL,
P_MFGR CHAR(25) NOT NULL,
P_BRAND CHAR(10) NOT NULL,
P_TYPE VARCHAR(25) NOT NULL,
P_SIZE INTEGER NOT NULL,
P_CONTAINER CHAR(10) NOT NULL,
P_RETAILPRICE DECIMAL(15,2) NOT NULL,
P_COMMENT VARCHAR(23) NOT NULL,
P_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE SUPPLIER ( S_SUPPKEY INTEGER NOT NULL,
S_NAME CHAR(25) NOT NULL,
S_ADDRESS VARCHAR(40) NOT NULL,
S_NATIONKEY INTEGER NOT NULL,
S_PHONE CHAR(15) NOT NULL,
S_ACCTBAL DECIMAL(15,2) NOT NULL,
S_COMMENT VARCHAR(101) NOT NULL,
S_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE PARTSUPP ( PS_PARTKEY INTEGER NOT NULL,
PS_SUPPKEY INTEGER NOT NULL,
PS_AVAILQTY INTEGER NOT NULL,
PS_SUPPLYCOST DECIMAL(15,2) NOT NULL,
PS_COMMENT VARCHAR(199) NOT NULL,
PS_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE CUSTOMER ( C_CUSTKEY INTEGER NOT NULL,
C_NAME VARCHAR(25) NOT NULL,
C_ADDRESS VARCHAR(40) NOT NULL,
C_NATIONKEY INTEGER NOT NULL,
C_PHONE CHAR(15) NOT NULL,
C_ACCTBAL DECIMAL(15,2) NOT NULL,
C_MKTSEGMENT CHAR(10) NOT NULL,
C_COMMENT VARCHAR(117) NOT NULL,
C_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE ORDERS ( O_ORDERKEY INTEGER NOT NULL,
O_CUSTKEY INTEGER NOT NULL,
O_ORDERSTATUS CHAR(1) NOT NULL,
O_TOTALPRICE DECIMAL(15,2) NOT NULL,
O_ORDERDATE DATE NOT NULL,
O_ORDERPRIORITY CHAR(15) NOT NULL,
O_CLERK CHAR(15) NOT NULL,
O_SHIPPRIORITY INTEGER NOT NULL,
O_COMMENT VARCHAR(79) NOT NULL,
O_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE LINEITEM ( L_ORDERKEY INTEGER NOT NULL,
L_PARTKEY INTEGER NOT NULL,
L_SUPPKEY INTEGER NOT NULL,
L_LINENUMBER INTEGER NOT NULL,
L_QUANTITY DECIMAL(15,2) NOT NULL,
L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL,
L_DISCOUNT DECIMAL(15,2) NOT NULL,
L_TAX DECIMAL(15,2) NOT NULL,
L_RETURNFLAG CHAR(1) NOT NULL,
L_LINESTATUS CHAR(1) NOT NULL,
L_SHIPDATE DATE NOT NULL,
L_COMMITDATE DATE NOT NULL,
L_RECEIPTDATE DATE NOT NULL,
L_SHIPINSTRUCT CHAR(25) NOT NULL,
L_SHIPMODE CHAR(10) NOT NULL,
L_COMMENT VARCHAR(44) NOT NULL,
L_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
2.创建约束
ALTER TABLE LINEITEM ADD PARTIAL CLUSTER KEY (L_SHIPDATE,L_COMMITDATE,L_RECEIPTDATE);
ALTER TABLE ORDERS ADD PARTIAL CLUSTER KEY (O_ORDERDATE);
3.导入数据
copy customer from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/customer.tbl' DELIMITERS '|';
copy lineitem from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/lineitem.tbl' DELIMITERS '|';
copy nation from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/nation.tbl' DELIMITERS '|';
copy orders from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/orders.tbl' DELIMITERS '|';
copy partsupp from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/partsupp.tbl' DELIMITERS '|';
copy part from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/part.tbl' DELIMITERS '|';
copy region from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/region.tbl' DELIMITERS '|';
copy supplier from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/supplier.tbl' DELIMITERS '|';
vacuum ANALYZE ;
五、执行22条测试sql
create database tpch;
--create tablespace tpch location '/data/tpch';
--alter database tpch set tablespace tpch;
CREATE TABLE NATION ( N_NATIONKEY INTEGER NOT NULL,
N_NAME CHAR(25) NOT NULL,
N_REGIONKEY INTEGER NOT NULL,
N_COMMENT VARCHAR(152),
N_NULL VARCHAR(10)
);
CREATE TABLE REGION ( R_REGIONKEY INTEGER NOT NULL,
R_NAME CHAR(25) NOT NULL,
R_COMMENT VARCHAR(152),
R_NULL VARCHAR(10)
);
CREATE TABLE PART ( P_PARTKEY INTEGER NOT NULL,
P_NAME VARCHAR(55) NOT NULL,
P_MFGR CHAR(25) NOT NULL,
P_BRAND CHAR(10) NOT NULL,
P_TYPE VARCHAR(25) NOT NULL,
P_SIZE INTEGER NOT NULL,
P_CONTAINER CHAR(10) NOT NULL,
P_RETAILPRICE DECIMAL(15,2) NOT NULL,
P_COMMENT VARCHAR(23) NOT NULL,
P_NULL VARCHAR(10)
);
CREATE TABLE SUPPLIER ( S_SUPPKEY INTEGER NOT NULL,
S_NAME CHAR(25) NOT NULL,
S_ADDRESS VARCHAR(40) NOT NULL,
S_NATIONKEY INTEGER NOT NULL,
S_PHONE CHAR(15) NOT NULL,
S_ACCTBAL DECIMAL(15,2) NOT NULL,
S_COMMENT VARCHAR(101) NOT NULL,
S_NULL VARCHAR(10)
);
CREATE TABLE PARTSUPP ( PS_PARTKEY INTEGER NOT NULL,
PS_SUPPKEY INTEGER NOT NULL,
PS_AVAILQTY INTEGER NOT NULL,
PS_SUPPLYCOST DECIMAL(15,2) NOT NULL,
PS_COMMENT VARCHAR(199) NOT NULL,
PS_NULL VARCHAR(10)
);
CREATE TABLE CUSTOMER ( C_CUSTKEY INTEGER NOT NULL,
C_NAME VARCHAR(25) NOT NULL,
C_ADDRESS VARCHAR(40) NOT NULL,
C_NATIONKEY INTEGER NOT NULL,
C_PHONE CHAR(15) NOT NULL,
C_ACCTBAL DECIMAL(15,2) NOT NULL,
C_MKTSEGMENT CHAR(10) NOT NULL,
C_COMMENT VARCHAR(117) NOT NULL,
C_NULL VARCHAR(10)
);
CREATE TABLE ORDERS ( O_ORDERKEY INTEGER NOT NULL,
O_CUSTKEY INTEGER NOT NULL,
O_ORDERSTATUS CHAR(1) NOT NULL,
O_TOTALPRICE DECIMAL(15,2) NOT NULL,
O_ORDERDATE DATE NOT NULL,
O_ORDERPRIORITY CHAR(15) NOT NULL,
O_CLERK CHAR(15) NOT NULL,
O_SHIPPRIORITY INTEGER NOT NULL,
O_COMMENT VARCHAR(79) NOT NULL,
O_NULL VARCHAR(10)
);
CREATE TABLE LINEITEM ( L_ORDERKEY INTEGER NOT NULL,
L_PARTKEY INTEGER NOT NULL,
L_SUPPKEY INTEGER NOT NULL,
L_LINENUMBER INTEGER NOT NULL,
L_QUANTITY DECIMAL(15,2) NOT NULL,
L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL,
L_DISCOUNT DECIMAL(15,2) NOT NULL,
L_TAX DECIMAL(15,2) NOT NULL,
L_RETURNFLAG CHAR(1) NOT NULL,
L_LINESTATUS CHAR(1) NOT NULL,
L_SHIPDATE DATE NOT NULL,
L_COMMITDATE DATE NOT NULL,
L_RECEIPTDATE DATE NOT NULL,
L_SHIPINSTRUCT CHAR(25) NOT NULL,
L_SHIPMODE CHAR(10) NOT NULL,
L_COMMENT VARCHAR(44) NOT NULL,
L_NULL VARCHAR(10)
);
copy customer from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/customer.tbl' DELIMITERS '|';
copy lineitem from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/lineitem.tbl' DELIMITERS '|';
copy nation from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/nation.tbl' DELIMITERS '|';
copy orders from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/orders.tbl' DELIMITERS '|';
copy partsupp from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/partsupp.tbl' DELIMITERS '|';
copy part from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/part.tbl' DELIMITERS '|';
copy region from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/region.tbl' DELIMITERS '|';
copy supplier from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/supplier.tbl' DELIMITERS '|';
ALTER TABLE REGION ADD PRIMARY KEY (R_REGIONKEY);
ALTER TABLE NATION ADD PRIMARY KEY (N_NATIONKEY);
ALTER TABLE PART ADD PRIMARY KEY (P_PARTKEY);
ALTER TABLE SUPPLIER ADD PRIMARY KEY (S_SUPPKEY);
ALTER TABLE PARTSUPP ADD PRIMARY KEY (PS_PARTKEY,PS_SUPPKEY);
ALTER TABLE CUSTOMER ADD PRIMARY KEY (C_CUSTKEY);
ALTER TABLE LINEITEM ADD PRIMARY KEY (L_ORDERKEY,L_LINENUMBER);
ALTER TABLE ORDERS ADD PRIMARY KEY (O_ORDERKEY);
ALTER TABLE PARTSUPP ADD FOREIGN KEY (PS_PARTKEY) REFERENCES PART(P_PARTKEY);
ALTER TABLE LINEITEM ADD FOREIGN KEY (L_ORDERKEY) REFERENCES ORDERS(O_ORDERKEY);
CREATE INDEX l_shipdate_idx ON LINEITEM(L_SHIPDATE);
vacuum ANALYZE ;
1.创建测试表
CREATE TABLE NATION ( N_NATIONKEY INTEGER NOT NULL,
N_NAME CHAR(25) NOT NULL,
N_REGIONKEY INTEGER NOT NULL,
N_COMMENT VARCHAR(152),
N_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE REGION ( R_REGIONKEY INTEGER NOT NULL,
R_NAME CHAR(25) NOT NULL,
R_COMMENT VARCHAR(152),
R_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE PART ( P_PARTKEY INTEGER NOT NULL,
P_NAME VARCHAR(55) NOT NULL,
P_MFGR CHAR(25) NOT NULL,
P_BRAND CHAR(10) NOT NULL,
P_TYPE VARCHAR(25) NOT NULL,
P_SIZE INTEGER NOT NULL,
P_CONTAINER CHAR(10) NOT NULL,
P_RETAILPRICE DECIMAL(15,2) NOT NULL,
P_COMMENT VARCHAR(23) NOT NULL,
P_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE SUPPLIER ( S_SUPPKEY INTEGER NOT NULL,
S_NAME CHAR(25) NOT NULL,
S_ADDRESS VARCHAR(40) NOT NULL,
S_NATIONKEY INTEGER NOT NULL,
S_PHONE CHAR(15) NOT NULL,
S_ACCTBAL DECIMAL(15,2) NOT NULL,
S_COMMENT VARCHAR(101) NOT NULL,
S_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE PARTSUPP ( PS_PARTKEY INTEGER NOT NULL,
PS_SUPPKEY INTEGER NOT NULL,
PS_AVAILQTY INTEGER NOT NULL,
PS_SUPPLYCOST DECIMAL(15,2) NOT NULL,
PS_COMMENT VARCHAR(199) NOT NULL,
PS_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE CUSTOMER ( C_CUSTKEY INTEGER NOT NULL,
C_NAME VARCHAR(25) NOT NULL,
C_ADDRESS VARCHAR(40) NOT NULL,
C_NATIONKEY INTEGER NOT NULL,
C_PHONE CHAR(15) NOT NULL,
C_ACCTBAL DECIMAL(15,2) NOT NULL,
C_MKTSEGMENT CHAR(10) NOT NULL,
C_COMMENT VARCHAR(117) NOT NULL,
C_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE ORDERS ( O_ORDERKEY INTEGER NOT NULL,
O_CUSTKEY INTEGER NOT NULL,
O_ORDERSTATUS CHAR(1) NOT NULL,
O_TOTALPRICE DECIMAL(15,2) NOT NULL,
O_ORDERDATE DATE NOT NULL,
O_ORDERPRIORITY CHAR(15) NOT NULL,
O_CLERK CHAR(15) NOT NULL,
O_SHIPPRIORITY INTEGER NOT NULL,
O_COMMENT VARCHAR(79) NOT NULL,
O_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
CREATE TABLE LINEITEM ( L_ORDERKEY INTEGER NOT NULL,
L_PARTKEY INTEGER NOT NULL,
L_SUPPKEY INTEGER NOT NULL,
L_LINENUMBER INTEGER NOT NULL,
L_QUANTITY DECIMAL(15,2) NOT NULL,
L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL,
L_DISCOUNT DECIMAL(15,2) NOT NULL,
L_TAX DECIMAL(15,2) NOT NULL,
L_RETURNFLAG CHAR(1) NOT NULL,
L_LINESTATUS CHAR(1) NOT NULL,
L_SHIPDATE DATE NOT NULL,
L_COMMITDATE DATE NOT NULL,
L_RECEIPTDATE DATE NOT NULL,
L_SHIPINSTRUCT CHAR(25) NOT NULL,
L_SHIPMODE CHAR(10) NOT NULL,
L_COMMENT VARCHAR(44) NOT NULL,
L_NULL VARCHAR(10)
)with (ORIENTATION = COLUMN);
2.创建约束
ALTER TABLE LINEITEM ADD PARTIAL CLUSTER KEY (L_SHIPDATE,L_COMMITDATE,L_RECEIPTDATE);
ALTER TABLE ORDERS ADD PARTIAL CLUSTER KEY (O_ORDERDATE);
3.导入数据
copy customer from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/customer.tbl' DELIMITERS '|';
copy lineitem from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/lineitem.tbl' DELIMITERS '|';
copy nation from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/nation.tbl' DELIMITERS '|';
copy orders from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/orders.tbl' DELIMITERS '|';
copy partsupp from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/partsupp.tbl' DELIMITERS '|';
copy part from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/part.tbl' DELIMITERS '|';
copy region from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/region.tbl' DELIMITERS '|';
copy supplier from '/home/tpch/TPC-H_Tools_v3.0.0/dbgen/supplier.tbl' DELIMITERS '|';
vacuum ANALYZE ;
五、执行22条测试sql
Q1:定价汇总报表查询
定价汇总报表查询是分组、排序、聚集操作并存的单表查询操作,报告已开票、发货和退回的业务量; 为给定日期发货的所有订单项提供汇总定价报告,按l_returnflag和l_linestatus分组并排序,列出了扩展价格、折扣扩展价格、折扣扩展价格加税、平均数量、平均扩展价格、平均折扣、各个分组的总行数。
Q1语句的特点是:带有分组、排序、聚集操作并存的单表查询操作。这个查询会导致表上的数据有95%到97%行被读取到。
--语句详解
select
l_returnflag, //返回标志
l_linestatus,
sum(l_quantity) as sum_qty, //总的数量
sum(l_extendedprice) as sum_base_price, //聚集函数操作
sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
avg(l_quantity) as avg_qty,
avg(l_extendedprice) as avg_price,
avg(l_discount) as avg_disc,
count(*) as count_order //每个分组所包含的行数
from
lineitem
where
l_shipdate <= date'1998-12-01' - interval '90' day //时间段是随机生成的
group by //分组操作
l_returnflag,
l_linestatus
order by //排序操作
l_returnflag,
l_linestatus;
示例sql:
select
l_returnflag,
l_linestatus,
sum(l_quantity) as sum_qty,
sum(l_extendedprice) as sum_base_price,
sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
avg(l_quantity) as avg_qty,
avg(l_extendedprice) as avg_price,
avg(l_discount) as avg_disc,
count(*) as count_order
from
lineitem
where
l_shipdate <= date '1998-12-01' - interval '103' day
group by
l_returnflag,
l_linestatus
order by
l_returnflag,
l_linestatus
LIMIT 1;
Q2:最低成本供应商查询
最低成本供应商查询是带有排序、聚集操作、子查询并存的多表查询操作,查找应该选择那个供应商来为给定地区的给定零件下订单;在给定的区域中,针对特定类型和尺寸的每个零件,找到能够以最低成本供应的供应商。如果该地区的多个供应商以相同的(最低)成本供货。查询列出了供应商的账户余额、名称和国家,零部件编号、制造商,供应商的地址、电话号码和评论信息。
Q2语句的特点是:带有排序、聚集操作、子查询并存的多表查询操作。查询语句没有从语法上限制返回多少条元组,但是TPC-H标准规定,查询结果只返回前100行(通常依赖于应用程序实现)。
--语句详解
select
s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment
/*查询供应者的帐户余额、名字、国家、零件的号码、生产者、供应者的地址、电话号码、备注信息 */
from
part, supplier, partsupp, nation, region //五表连接
where
p_partkey = ps_partkey
and s_suppkey = ps_suppkey
and p_size = [SIZE] //指定大小,在区间[1, 50]内随机选择
and p_type like '%[TYPE]' //指定类型,在TPC-H标准指定的范围内随机选择
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = '[REGION]' //指定地区,在TPC-H标准指定的范围内随机选择
and ps_supplycost = ( //子查询
select
min(ps_supplycost) //聚集函数
from
partsupp, supplier, nation, region //与父查询的表有重叠
where
p_partkey = ps_partkey
and s_suppkey = ps_suppkey
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = '[REGION]'
)
order by //排序
s_acctbal desc,
n_name,
s_name,
p_partkey;
示例sql:
select
s_acctbal,
s_name,
n_name,
p_partkey,
p_mfgr,
s_address,
s_phone,
s_comment
from
part,
supplier,
partsupp,
nation,
region,
(
select
ps_partkey,
min(ps_supplycost) as min
from
partsupp,
supplier,
nation,
region
where
s_suppkey = ps_suppkey
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'EUROPE'
group by
ps_partkey
) temp
where
p_partkey = partsupp.ps_partkey
and s_suppkey = ps_suppkey
and p_size = 47
and p_type like '%BRASS'
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'EUROPE'
and ps_supplycost = temp.min
and p_partkey = temp.ps_partkey
order by
s_acctbal desc,
n_name,
s_name,
p_partkey
LIMIT 100;
Q3:运输优先级查询
运输优先级查询是带有分组、排序、聚集操作并存的三表查询操作,检索价值最高的未发货订单;在给定日期尚未发货的订单中收入最大的订单的运输优先级和潜在收入(l_extendedprice * (1-l_discount)的总和),订单按照收入的降序排序。
Q3语句的特点是:带有分组、排序、聚集操作并存的三表查询操作。查询语句没有从语法上限制返回多少条元组,但是TPC-H标准规定,查询结果只返回前10行(通常依赖于应用程序实现)。
--语句详解
select
l_orderkey,
sum(l_extendedprice*(1-l_discount)) as revenue, //潜在的收入,聚集操作
o_orderdate,
o_shippriority
from
customer, orders, lineitem //三表连接
where
c_mktsegment = '[SEGMENT]' //在TPC-H标准指定的范围内随机选择
and c_custkey = o_custkey
and l_orderkey = o_orderkey
and o_orderdate < date '[DATE]' //指定日期段,在在[1995-03-01, 1995-03-31]中随机选择
and l_shipdate > date '[DATE]'
group by //分组操作
l_orderkey, //订单标识
o_orderdate, //订单日期
o_shippriority //运输优先级
order by //排序操作
revenue desc, //降序排序,把潜在最大收入列在前面
o_orderdate;
示例sql:
select
l_orderkey,
sum(l_extendedprice * (1 - l_discount)) as revenue,
o_orderdate,
o_shippriority
from
customer,
orders,
lineitem
where
c_mktsegment = 'BUILDING'
and c_custkey = o_custkey
and l_orderkey = o_orderkey
and o_orderdate < date '1995-03-20'
and l_shipdate > date '1995-03-20'
group by
l_orderkey,
o_orderdate,
o_shippriority
order by
revenue desc,
o_orderdate
LIMIT 10;
Q4:订单优先级查询
订单优先级查询是带有分组、排序、聚集操作、子查询并存的单表查询操作,确定订单优先系统的工作情况并评估客户满意度;在给定季度中的订购数量,其中客户在承诺日志之后收到至少一个订单项,列出了按优先级升序排序的每个订单优先级的此类订单的计数。
Q4语句的特点是:带有分组、排序、聚集操作、子查询并存的单表查询操作。子查询是相关子查询。
--语句详解
select
o_orderpriority, //订单优先级
count(*) as order_count //订单优先级计数
from orders //单表查询
where
o_orderdate >= date '[DATE]'
and o_orderdate < date '[DATE]' + interval '3' month //指定订单的时间段+三个月,DATE是在1993年1月和1997年10月之间随机选择的一个月的第一天
and exists ( //子查询
select
*
from
lineitem
where
l_orderkey = o_orderkey
and l_commitdate < l_receiptdate
)
group by //按订单优先级分组
o_orderpriority
order by //按订单优先级排序
o_orderpriority;
示例sql:
select
o_orderpriority,
count(*) as order_count
from
orders
where
o_orderdate >= date '1995-12-01'
and o_orderdate < date '1995-12-01' + interval '3' month
and exists
(
select
*
from
lineitem
where
l_orderkey = o_orderkey
and l_commitdate < l_receiptdate
limit 1
)
group by
o_orderpriority
order by
o_orderpriority
LIMIT 1;
Q5:本地供应商收入量查询
本地供应商收入量查询是带有分组、排序、聚集操作、子查询并存的多表连接查询操作,列出了通过本地供应商完成的收入量;为一个地区的每个国家列出了由订单项交易产生的收入量,以确定是否在给定区域建立本地配送中心。
Q5语句的特点是:带有分组、排序、聚集操作、子查询并存的多表连接查询操作。
--语句详解
select
n_name,
sum(l_extendedprice * (1 - l_discount)) as revenue //聚集操作
from
customer,orders,lineitem,supplier,nation,region //六表连接
where
c_custkey = o_custkey
and l_orderkey = o_orderkey
and l_suppkey = s_suppkey
and c_nationkey = s_nationkey
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = '[REGION]' //指定地区,在TPC-H标准指定的范围内随机选择
and o_orderdate >= date '[DATE]' //DATE是从1993年到1997年中随机选择的一年的1月1日
and o_orderdate < date '[DATE]' + interval '1' year
group by //按名字分组
n_name
order by //按收入降序排序,注意分组和排序子句不同
revenue desc;
示例sql:
select
n_name,
sum(l_extendedprice * (1 - l_discount)) as revenue
from
customer,
orders,
lineitem,
supplier,
nation,
region
where
c_custkey = o_custkey
and l_orderkey = o_orderkey
and l_suppkey = s_suppkey
and c_nationkey = s_nationkey
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'AMERICA'
and o_orderdate >= date '1997-01-01'
and o_orderdate < date '1997-01-01' + interval '1' year
group by
n_name
order by
revenue desc
LIMIT 1;
Q6:预测收入变化查询
预测收入变化查询是带有聚集操作的单表查询操作,量化了在给定年份中给定百分比范围内消除某些公司范围内的折扣所导致的收入增长量,用于寻找增加收入的方法;在给定的年份发货的所有订单项,折扣介于“DISCOUNT-0.01”和“DISCOUNT+0.01”之间,如果l_quantity小于quantity的订单的折扣被消除后总收入增加的数量。
Q6语句的特点是:带有聚集操作的单表查询操作。查询语句使用了BETWEEN-AND操作符,有的数据库可以对BETWEEN-AND进行优化。
--语句详解
select
sum(l_extendedprice*l_discount) as revenue //潜在的收入增加量
from
lineitem //单表查询
where
l_shipdate >= date '[DATE]' //DATE是从[1993, 1997]中随机选择的一年的1月1日
and l_shipdate < date '[DATE]' + interval '1' year //一年内
and l_discount between [DISCOUNT] - 0.01 and [DISCOUNT] + 0.01 //between
and l_quantity < [QUANTITY]; // QUANTITY在区间[24, 25]中随机选择
示例sql:
select
sum(l_extendedprice * l_discount) as revenue
from
lineitem
where
l_shipdate >= date '1997-01-01'
and l_shipdate < date '1997-01-01' + interval '1' year
and l_discount between 0.07 - 0.01 and 0.07 + 0.01
and l_quantity < 24
LIMIT 1;
Q7:批量出货查询
批量出货查询是带有分组、排序、聚集、子查询操作并存的多表查询操作,确定在某些国家直接运输的货物的价值以帮助重新谈判运输合同;对于两个给定的国家,在1995年到1996年期间,从其中一个国家的供应商想另一个国家的客户运送零件的订单项获得的总折扣收入。
Q7语句的特点是:带有分组、排序、聚集、子查询操作并存的多表查询操作。子查询的父层查询不存在其他查询对象,是格式相对简单的子查询。
--语句详解
select
supp_nation, //供货商国家
cust_nation, //顾客国家
l_year, sum(volume) as revenue //年度、年度的货运收入
from ( //子查询
select
n1.n_name as supp_nation,
n2.n_name as cust_nation,
extract(year from l_shipdate) as l_year,
l_extendedprice * (1 - l_discount) as volume
from
supplier,lineitem,orders,customer,nation n1,nation n2 //六表连接
where
s_suppkey = l_suppkey
and o_orderkey = l_orderkey
and c_custkey = o_custkey
and s_nationkey = n1.n_nationkey
and c_nationkey = n2.n_nationkey
and ( // NATION2和NATION1的值不同,表示查询的是跨国的货运情况
(n1.n_name = '[NATION1]' and n2.n_name = '[NATION2]')
or (n1.n_name = '[NATION2]' and n2.n_name = '[NATION1]')
)
and l_shipdate between date '1995-01-01' and date '1996-12-31'
) as shipping
group by
supp_nation,
cust_nation,
l_year
order by
supp_nation,
cust_nation,
l_year;
示例sql:
select
supp_nation,
cust_nation,
l_year,
sum(volume) as revenue
from
(
select
n1.n_name as supp_nation,
n2.n_name as cust_nation,
extract(year from l_shipdate) as l_year,
l_extendedprice * (1 - l_discount) as volume
from
supplier,
lineitem,
orders,
customer,
nation n1,
nation n2
where
s_suppkey = l_suppkey
and o_orderkey = l_orderkey
and c_custkey = o_custkey
and s_nationkey = n1.n_nationkey
and c_nationkey = n2.n_nationkey
and
(
(n1.n_name = 'CHINA' and n2.n_name = 'INDONESIA')
or (n1.n_name = 'INDONESIA' and n2.n_name = 'CHINA')
)
and l_shipdate between date '1995-01-01' and date '1996-12-31'
) as shipping
group by
supp_nation,
cust_nation,
l_year
order by
supp_nation,
cust_nation,
l_year
LIMIT 1;
Q8:全国市场份额查询
全国市场份额查询带有分组、排序、聚集、子查询操作并存的查询操作,确定给定区域内给定国家的市场份额在两年内对于给定零件类型的变化情况; 给定区域内给定国家的市场份额被定义为收入的一部分,即 l_extendedprice * (1-l_discount)的总和。
Q8语句的特点是:带有分组、排序、聚集、子查询操作并存的查询操作。子查询的父层查询不存在其他查询对象,是格式相对简单的子查询,但子查询自身是多表连接的查询。
--语句详解:
select
o_year, //年份
sum(case
when nation = '[NATION]'//指定国家,在TPC-H标准指定的范围内随机选择
then volume
else 0
end) / sum(volume) as mkt_share //市场份额:特定种类的产品收入的百分比;聚集操作
from ( //子查询
select
extract(year from o_orderdate) as o_year, //分解出年份
l_extendedprice * (1-l_discount) as volume, //特定种类的产品收入
n2.n_name as nation
from
part,supplier,lineitem,orders,customer,nation n1,nation n2,region //八表连接
where
p_partkey = l_partkey
and s_suppkey = l_suppkey
and l_orderkey = o_orderkey
and o_custkey = c_custkey
and c_nationkey = n1.n_nationkey
and n1.n_regionkey = r_regionkey
and r_name = '[REGION]' //指定地区,在TPC-H标准指定的范围内随机选择
and s_nationkey = n2.n_nationkey
and o_orderdate between date '1995-01-01' and date '1996-12-31' //只查95、96年的情况
and p_type = '[TYPE]' //指定零件类型,在TPC-H标准指定的范围内随机选择
) as all_nations
group by //按年分组
o_year
order by //按年排序
o_year;
示例sql:
select
o_year,
sum(case
when nation = 'INDONESIA' then volume
else 0
end) / sum(volume) as mkt_share
from
(
select
extract(year from o_orderdate) as o_year,
l_extendedprice * (1 - l_discount) as volume,
n2.n_name as nation
from
part,
supplier,
lineitem,
orders,
customer,
nation n1,
nation n2,
region
where
p_partkey = l_partkey
and s_suppkey = l_suppkey
and l_orderkey = o_orderkey
and o_custkey = c_custkey
and c_nationkey = n1.n_nationkey
and n1.n_regionkey = r_regionkey
and r_name = 'ASIA'
and s_nationkey = n2.n_nationkey
and o_orderdate between date '1995-01-01' and date '1996-12-31'
and p_type = 'PROMO POLISHED TIN'
) as all_nations
group by
o_year
order by
o_year
LIMIT 1;
Q9:产品类型利润度量查询
产品类型利润度量查询是带有分组、排序、聚集、子查询操作并存的查询操作,确定按供应商国家和年份细分的给定零件系列的利润。
Q9语句的特点是:带有分组、排序、聚集、子查询操作并存的查询操作。子查询的父层查询不存在其他查询对象,是格式相对简单的子查询,但子查询自身是多表连接的查询。子查询中使用了LIKE操作符,有的查询优化器不支持对LIKE操作符进行优化。
--语句详解
select
nation,
o_year,
sum(amount) as sum_profit //每个国家每一年所有被定购的零件在一年中的总利润
from(
select
n_name as nation, //国家
extract(year from o_orderdate) as o_year, //取出年份
l_extendedprice * (1 - l_discount) - ps_supplycost * l_quantity as amount //利润
from
part,supplier,lineitem,partsupp,orders,nation //六表连接
where
s_suppkey = l_suppkey
and ps_suppkey = l_suppkey
and ps_partkey = l_partkey
and p_partkey = l_partkey
and o_orderkey = l_orderkey
and s_nationkey = n_nationkey
and p_name like '%[COLOR]%' //LIKE操作,查询优化器可能进行优化
) as profit
group by //按国家和年份分组
nation,
o_year
order by //按国家和年份排序,年份大者靠前
nation,
o_year desc;
示例sql:
select
nation,
o_year,
sum(amount) as sum_profit
from
(
select
n_name as nation,
extract(year from o_orderdate) as o_year,
l_extendedprice * (1 - l_discount) - ps_supplycost * l_quantity as amount
from
part,
supplier,
lineitem,
partsupp,
orders,
nation
where
s_suppkey = l_suppkey
and ps_suppkey = l_suppkey
and ps_partkey = l_partkey
and p_partkey = l_partkey
and o_orderkey = l_orderkey
and s_nationkey = n_nationkey
and p_name like '%thistle%'
) as profit
group by
nation,
o_year
order by
nation,
o_year desc
LIMIT 1;
Q10:退货报告查询
退货报告查询是带有分组、排序、聚集操作并存的多表连接查询操作,识别可能对运送给他们的零件有问题的客户;根据对给定季度收入损失的影响,找出排名靠前的已退回零件的客户。
Q10语句的特点是:带有分组、排序、聚集操作并存的多表连接查询操作。查询语句没有从语法上限制返回多少条元组,但是TPC-H标准规定,查询结果只返回前10行(通常依赖于应用程序实现)。
--语句详解:
select
c_custkey, c_name, //客户信息
sum(l_extendedprice * (1 - l_discount)) as revenue, //收入损失
c_acctbal,
n_name, c_address, c_phone, c_comment //国家、地址、电话、意见信息等
from
customer, orders, lineitem, nation
where
c_custkey = o_custkey
and l_orderkey = o_orderkey
and o_orderdate >= date '[DATE]' // DATE是位于1993年一月到1994年十二月中任一月的一号
and o_orderdate < date '[DATE]' + interval '3' month //3个月内
and l_returnflag = 'R' //货物被回退
and c_nationkey = n_nationkey
group by
c_custkey,
c_name,
c_acctbal,
c_phone,
n_name,
c_address,
c_comment
order by
revenue desc;
示例sql:
select
c_custkey,
c_name,
sum(l_extendedprice * (1 - l_discount)) as revenue,
c_acctbal,
n_name,
c_address,
c_phone,
c_comment
from
customer,
orders,
lineitem,
nation
where
c_custkey = o_custkey
and l_orderkey = o_orderkey
and o_orderdate >= date '1994-06-01'
and o_orderdate < date '1994-06-01' + interval '3' month
and l_returnflag = 'R'
and c_nationkey = n_nationkey
group by
c_custkey,
c_name,
c_acctbal,
c_phone,
n_name,
c_address,
c_comment
order by
revenue desc
LIMIT 20;
Q11:库存价值查询
库存价值查询是带有分组、排序、聚集、子查询操作并存的多表连接查询操作,查找给定国家/地区供应商的库存价值; 扫描给定国家的供应商的可用库存来查找占有所有可用零件总价值的重要百分比的所有零件。
Q11语句的特点是:带有分组、排序、聚集、子查询操作并存的多表连接查询操作。子查询位于分组操作的HAVING条件中。
--语句详解
select
ps_partkey,
sum(ps_supplycost * ps_availqty) as value //聚集操作,商品的总价值
from
partsupp, supplier, nation
where
ps_suppkey = s_suppkey
and s_nationkey = n_nationkey
and n_name = '[NATION]'
group by
ps_partkey
having //带有HAVING子句的分组操作
sum(ps_supplycost * ps_availqty) > ( //HAVING子句中包括有子查询
select
sum(ps_supplycost * ps_availqty) * [FRACTION] //子查询中存在聚集操作;FRACTION为0.0001/SF1
from
partsupp, supplier, nation //与父查询的表连接一致
where //与父查询的WHEWR条件一致
ps_suppkey = s_suppkey
and s_nationkey = n_nationkey
and n_name = '[NATION]' //指定国家
)
order by //按商品的价值降序排序
value desc;
示例sql:
select
ps_partkey,
sum(ps_supplycost * ps_availqty) as value
from
partsupp,
supplier,
nation
where
ps_suppkey = s_suppkey
and s_nationkey = n_nationkey
and n_name = 'ALGERIA'
group by
ps_partkey having
sum(ps_supplycost * ps_availqty) >
(
select
sum(ps_supplycost * ps_availqty) * 0.0001000000
from
partsupp,
supplier,
nation
where
ps_suppkey = s_suppkey
and s_nationkey = n_nationkey
and n_name = 'ALGERIA'
)
order by
value desc
LIMIT 1;
Q12:运送方式和订单优先级查询
运送方式和订单优先级查询是带有分组、排序、聚集操作并存的两表连接查询操作,确定选择较便宜的运送方式是否会对关键优先级订单产生负面影响,导致消费者更多的在合同日期之后收到货物。
Q12语句的特点是:带有分组、排序、聚集操作并存的两表连接查询操作。
--语句详解
select
l_shipmode,
sum(//聚集操作
case when
o_orderpriority ='1-URGENT' //OR运算,二者满足其一即可,选出URGENT或HIGH的
or o_orderpriority ='2-HIGH'
then 1
else 0
end) as high_line_count,
sum(
case when
o_orderpriority <> '1-URGENT' //AND运算,二者都不满足,非URGENT非HIGH的
and o_orderpriority <> '2-HIGH'
then 1
else 0
end) as low_line_count
from
orders,lineitem
where
o_orderkey = l_orderkey
and l_shipmode in ('[SHIPMODE1]', '[SHIPMODE2]')
/* 指定货运模式的类型,在TPC-H标准指定的范围内随机选择,SHIPMODE2必须有别于SHIPMODE1 */
and l_commitdate < l_receiptdate
and l_shipdate < l_commitdate
and l_receiptdate >= date '[DATE]' //从1993年到1997年中任一年的一月一号
and l_receiptdate < date '[DATE]' + interval '1' year //1年之内
group by //分组操作
l_shipmode
order by //排序操作
l_shipmode;
示例sql:
select
l_shipmode,
sum(case when o_orderpriority = '1-URGENT' or o_orderpriority = '2-HIGH' then 1 else 0 end) as high_line_count,
sum(case when o_orderpriority <> '1-URGENT' and o_orderpriority <> '2-HIGH' then 1 else 0 end) as low_line_count
from
orders,
lineitem
where
o_orderkey = l_orderkey
and l_shipmode in ('RAIL', 'SHIP')
and l_commitdate < l_receiptdate
and l_shipdate < l_commitdate
and l_receiptdate >= date '1994-01-01'
and l_receiptdate < date '1994-01-01' + interval '1' year
group by
l_shipmode
order by
l_shipmode
LIMIT 1;
Q13:客户分布查询
客户分布查询是带有分组、排序、聚集、子查询、左外连接操作并存的查询操作;根究客户的订单数量确定客户的分布,计算并报告有多少客户没有订单,有多个客户有1/2/3 等个订单。
Q13语句的特点是:带有分组、排序、聚集、子查询、左外连接操作并存的查询操作。
--语句详解
select
c_count, count(*) as custdist //聚集操作,统计每个组的个数
from (//子查询
select
c_custkey,
count(o_orderkey)
from
customer left outer join orders
on //子查询中包括左外连接操作
c_custkey = o_custkey
and o_comment not like ‘%[WORD1]%[WORD2]%’ //LIKE操作
//WORD1 为以下四个可能值中任意一个:special、pending、unusual、express
//WORD2 为以下四个可能值中任意一个:packages、requests、accounts、deposits
group by //子查询中的分组操作
c_custkey
) as c_orders (c_custkey, c_count)
group by //分组操作
c_count
order by //排序操作
custdist desc, //从大到小降序排序
c_count desc;
TPC-H标准定义了Q13语句等价的变形SQL,与上述查询语句格式上不相同,上述语句使用子查询作为查询的对象,变形的SQL把子查询部分变为视图,然后基于视图做查询,这种做法的意义在于有些数据库不支持如上语法,但存在等价的其他语法,如MySQL就不支持如上语法,需要使用如下等价形式。
create view orders_per_cust:s (custkey, ordercount) as //创建视图,相当与标准Q13的子查询内容
select
c_custkey,
count(o_orderkey)
from
customer left outer join orders on
c_custkey = o_custkey
and o_comment not like '%:1%:2%'
group by
c_custkey;
select
ordercount,
count(*) as custdist
from
orders_per_cust:s //对视图进行查询
group by
ordercount
order by
custdist desc,
ordercount desc;
drop view orders_per_cust:s;
示例sql:
select
c_count,
count(*) as custdist
from
(
select
c_custkey,
count(o_orderkey)
from
customer left outer join orders on
c_custkey = o_custkey
and o_comment not like '%express%packages%'
group by
c_custkey
) as c_orders (c_custkey, c_count)
group by
c_count
order by
custdist desc,
c_count desc
LIMIT 1;
Q14:促销效果查询
促销效果查询是带有分组、排序、聚集、子查询、左外连接操作并存的查询操作,监控市场对促销的反应;确定在给定年份和月份的收入中有多少百分比来之与促销部分。
Q14语句的特点是:带有分组、排序、聚集、子查询、左外连接操作并存的查询操作。
语句详解:
select
100.00 * sum(
case when p_type like 'PROMO%' //促销零件
then l_extendedprice*(1-l_discount) //某一特定时间的收入
else 0
end) / sum(l_extendedprice * (1 - l_discount)) as promo_revenue
from
lineitem, part
where
l_partkey = p_partkey
and l_shipdate >= date '[DATE]' // DATE是从1993年到1997年中任一年的任一月的一号
and l_shipdate < date '[DATE]' + interval '1' month;
示例sql:
select
100.00 * sum(case when p_type like 'PROMO%' then l_extendedprice * (1 - l_discount) else 0 end) / sum(l_extendedprice * (1 - l_discount)) as promo_revenue
from
lineitem,
part
where
l_partkey = p_partkey
and l_shipdate >= date '1994-02-01'
and l_shipdate < date '1994-02-01' + interval '1' month
LIMIT 1;
Q15:*供应商查询
*供应商查询是带有分排序、聚集、聚集子查询操作并存的普通表与视图的连接操作,确定*供应商以对其进行奖励、给予更多业务或获得特殊认可;在给定的年费的给定季度对总出货量贡献最大的供应商。
Q15语句的特点是:带有分排序、聚集、聚集子查询操作并存的普通表与视图的连接操作。
--语句详解:
create view revenue[STREAM_ID](supplier_no, total_revenue) as //创建复杂视图(带有分组操作)
select
l_suppkey,
sum(l_extendedprice * (1 - l_discount)) //获取供货商为公司带来的总利润
from
lineitem
where
l_shipdate >= date '[DATE]' //DATE 是从1993年一月到1997年十月中任一月的一号
and l_shipdate < date '[DATE]' + interval '3' month //3个月内
group by //分组键与查询对象之一相同
l_suppkey;
//查询语句
select
s_suppkey,
s_name,
s_address,
s_phone,
total_revenue
from
supplier,revenue[STREAM_ID] //普通表与复杂视图进行连接操作
where
s_suppkey = supplier_no
and total_revenue = (//聚集子查询
select
max(total_revenue)
from
revenue[STREAM_ID] //聚集子查询从视图获得数据
)
order by
s_suppkey;
//删除视图
drop view revenue[STREAM_ID];
TPC-H标准定义了Q15语句等价的变形SQL,使用了WITH子句,然后用WITH的对象与表进行连接。变形SQL的语句如下:
WITH revenue (supplier_no, total_revenue) as (
SELECT
l_suppkey,
SUM(l_extendedprice * (1-l_discount))
FROM
lineitem
WHERE
l_shipdate >= date ':1'
AND l_shipdate < date ':1' + interval '3' month
GROUP BY
l_suppkey
)
SELECT
s_suppkey,
s_name,
s_address,
s_phone,
total_revenue
FROM
supplier,
revenue
WHERE
s_suppkey = supplier_no
AND total_revenue = (
SELECT
MAX(total_revenue)
FROM
revenue
)
ORDER BY
s_suppkey;
示例sql:
create or replace view revenue0 (supplier_no, total_revenue) as
select
l_suppkey,
sum(l_extendedprice * (1 - l_discount))
from
lineitem
where
l_shipdate >= date '1994-02-01'
and l_shipdate < date '1994-02-01' + interval '3' month
group by
l_suppkey;
select
s_suppkey,
s_name,
s_address,
s_phone,
total_revenue
from
supplier,
revenue0
where
s_suppkey = supplier_no
and total_revenue =
(
select
max(total_revenue)
from
revenue0
)
order by
s_suppkey
LIMIT 1;
Q16:零部件/供货商关系查询
零部件/供货商关系查询是带有分组、排序、聚集、去重、NOT IN子查询操作并存的两表连接操作;找出有多少供应商可以提供具有给定属性的零件。
Q16语句的特点是:带有分组、排序、聚集、去重、NOT IN子查询操作并存的两表连接操作。
--语句详解
select
p_brand,
p_type,
p_size,
count(distinct ps_suppkey) as supplier_cnt //聚集、去重操作
from
partsupp,
part
where
p_partkey = ps_partkey
and p_brand <> '[BRAND]'
// BRAND=Brand#MN ,M和N是两个字母,代表两个数值,相互独立,取值在1到5之间
and p_type not like '[TYPE]%' //消费者不感兴趣的类型和尺寸
and p_size in ([SIZE1], [SIZE2], [SIZE3], [SIZE4], [SIZE5], [SIZE6], [SIZE7], [SIZE8])
//TYPEX是在1到50之间任意选择的一组八个不同的值
and ps_suppkey not in ( //NOT IN子查询,消费者排除某些供货商
select
s_suppkey
from
supplier
where
s_comment like '%Customer%Complaints%'
)
group by //分组操作
p_brand,
p_type,
p_size
order by //排序操作
supplier_cnt desc, //按数量降序排列,按品牌、种类、尺寸升序排列
p_brand,
p_type,
p_size;
示例sql:
select
p_brand,
p_type,
p_size,
count(distinct ps_suppkey) as supplier_cnt
from
partsupp,
part
where
p_partkey = ps_partkey
and p_brand <> 'Brand#55'
and p_type not like 'MEDIUM PLATED%'
and p_size in (35, 17, 43, 49, 19, 41, 30, 47)
and ps_suppkey not in
(
select
s_suppkey
from
supplier
where
s_comment like '%Customer%Complaints%'
)
group by
p_brand,
p_type,
p_size
order by
supplier_cnt desc,
p_brand,
p_type,
p_size
LIMIT 1;
Q17:小额订单收入查询
小额订单收入查询是带有聚集、聚集子查询操作并存的两表连接操作;确定如果不在为少量特定零件完成订单,平均每年将损失多少收入,通过集中在更大的出货量上来减少管理费用;给定品牌和给定容器类型的零部件,确定在7年内数据库中所有订单订购的此类零件的平均订单数量,如果不再接收低于20%平均水平的订单,平均每年的总收入损失多少。
Q17语句的特点是:带有聚集、聚集子查询操作并存的两表连接操作。
--语句详解
select
sum(l_extendedprice) / 7.0 as avg_yearly //聚集操作
from
lineitem, part
where
p_partkey = l_partkey
and p_brand = '[BRAND]' /*指定品牌。 BRAND=’Brand#MN’ ,M和N是两个字母,代表两个数值,相互独立,取值在1到5之间 */
and p_container = '[CONTAINER]' //指定包装类型。在TPC-H标准指定的范围内随机选择
and l_quantity < ( //聚集子查询
select
0.2 * avg(l_quantity)
from
lineitem
where
l_partkey = p_partkey
);
示例sql:
select
sum(l_extendedprice) / 7.0 as avg_yearly
from
lineitem,
part,
(SELECT l_partkey AS agg_partkey, 0.2 * avg(l_quantity) AS avg_quantity FROM lineitem GROUP BY l_partkey) part_agg
where
p_partkey = l_partkey
and agg_partkey = l_partkey
and p_brand = 'Brand#53'
and p_container = 'JUMBO JAR'
and l_quantity < avg_quantity
LIMIT 1;
Q18:大批量客户查询
大批量客户查询是带有分组、排序、聚集、IN子查询操作并存的三表连接操作,根据客户的大批量订单对客户进行排名。
Q18语句的特点是:带有分组、排序、聚集、IN子查询操作并存的三表连接操作。查询语句没有从语法上限制返回多少条元组,但是TPC-H标准规定,查询结果只返回前100行(通常依赖于应用程序实现)。
--语句详解
select
c_name, c_custkey, o_orderkey, o_orderdate, o_totalprice, //基本信息
sum(l_quantity) //订货总数
from
customer, orders, lineitem
where
o_orderkey in ( //带有分组操作的IN子查询
select
l_orderkey
from
lineitem
group by
l_orderkey
having
sum(l_quantity) > [QUANTITY] // QUANTITY是位于312到315之间的任意值
)
and c_custkey = o_custkey
and o_orderkey = l_orderkey
group by
c_name,
c_custkey,
o_orderkey,
o_orderdate,
o_totalprice
order by
o_totalprice desc,
o_orderdate;
示例sql:
select
c_name,
c_custkey,
o_orderkey,
o_orderdate,
o_totalprice,
sum(l_quantity)
from
customer,
orders,
lineitem
where
o_orderkey in
(
select
l_orderkey
from
lineitem
group by
l_orderkey having
sum(l_quantity) > 313
)
and c_custkey = o_custkey
and o_orderkey = l_orderkey
group by
c_name,
c_custkey,
o_orderkey,
o_orderdate,
o_totalprice
order by
o_totalprice desc,
o_orderdate
LIMIT 100;
Q19:折扣收入查询
折扣收入查询是带有分组、排序、聚集、IN子查询操作并存的三表连接操作,归因于以特定方式处理的选定零部件的总折扣收入。本查询是用数据挖掘工具产生格式化代码的一个例子;对一些空运或人工运输零件三个不同种类的所有订单的总折扣收入。零件的选择考虑特定品牌、包装和尺寸范围。
Q19语句的特点是:带有分组、排序、聚集、IN子查询操作并存的三表连
推荐阅读
-
简单介绍Oracle中listagg和wmsys.wm_concat连接字符串函数的使用方法
-
Intellij IDEA 插件开发入门详解 - 如何添加 Application 和 Project Component,并创建 Action? 在本文中,我们将详细介绍如何在 IntelliJ IDEA 中添加 Application 和 Project Component,并且通过这些组件来创建一个简单的 Action。 首先,我们将在 src 目录上使用 Alt+Insert 快捷键打开 New 对话框,然后从中选择 Application Component 并输入名称如 MyComponent。接下来,我们在 MyComponent 类中添加一个 sayHello 方法并编写相关逻辑。 然后,我们需要为我们的插件添加一个 Action,使用户可以通过菜单或其它方式访问它。为此,我们将创建一个新的类 SayHelloAction 继承自 AnAction 类,并在 actionPerformed 方法中获取 Application 和 MyComponent 对象,最后调用 MyComponent 的 sayHello 方法。 最后,我们需要为我们的插件配置相关的文件以确保它可以正常运行。在本文中,我们将详细介绍如何进行这些配置。
-
【2022新手指南】Java编程进阶之路 - 六、技术架构篇 ### MySQL索引底层解析与优化实战 - 你会讲解MySQL索引的数据结构吗?性能调优技巧知多少? - Redis深度揭秘:你知道多少?从基础到哨兵、主从复制全梳理 - Redis持久化及哨兵模式详解,还有集群搭建和Leader选举黑箱打开 - Zookeeper是个啥?特性和应用场景大公开 - ZooKeeper集群搭建攻略及 Leader选举、读写一致性、共享锁实现细节 - 探究ZooKeeper中的Leader选举机制及其在分布式环境中的作用 - Zab协议深入剖析:原理、功能与在Zookeeper中的核心地位 - RabbitMQ全方位解读:工作模式、消费限流、可靠投递与配置策略 - 设计者视角:RabbitMQ过期时间、死信队列与延时队列实践指南 - RocketMQ特性和应用场景揭示:理解其精髓与差异化优势 - Kafka详细介绍:特性及广泛应用于实时数据处理的场景解析 - ElasticSearch实力揭秘:特性概述与作为搜索引擎的广泛应用 - MongoDB认知升级:非关系型数据库的优势阐述,安装与使用实战教学 - BIO/NIO/AIO网络模型对比:掌握它们的区别与在网络编程中的实际应用 - Netty带你飞:理解其超快速度背后的秘密,包括线程模型分析 - 网络通信黑科技:Netty编解码原理与常用编解码器的应用,Protostuff实战演示 - 解密Netty粘包与拆包现象,怎样有效应对这一常见问题 - 自定义Netty心跳检测机制,轻松调整检测间隔时间的艺术 - Dubbo轻骑兵介绍:核心特性概览,服务降级实战与其实现益处 - Dubbo三大神器解读:本地存根与本地伪装的实战运用与优势呈现 ----------------------- 七、结语与回顾
-
SSM三大框架基础面试题-一、Spring篇 什么是Spring框架? Spring是一种轻量级框架,提高开发人员的开发效率以及系统的可维护性。 我们一般说的Spring框架就是Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块是核心容器、数据访问/集成、Web、AOP(面向切面编程)、工具、消息和测试模块。比如Core Container中的Core组件是Spring所有组件的核心,Beans组件和Context组件是实现IOC和DI的基础,AOP组件用来实现面向切面编程。 Spring的6个特征: 核心技术:依赖注入(DI),AOP,事件(Events),资源,i18n,验证,数据绑定,类型转换,SpEL。 测试:模拟对象,TestContext框架,Spring MVC测试,WebTestClient。 数据访问:事务,DAO支持,JDBC,ORM,编组XML。 Web支持:Spring MVC和Spring WebFlux Web框架。 集成:远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。 语言:Kotlin,Groovy,动态语言。 列举一些重要的Spring模块? Spring Core:核心,可以说Spring其他所有的功能都依赖于该类库。主要提供IOC和DI功能。 Spring Aspects:该模块为与AspectJ的集成提供支持。 Spring AOP:提供面向切面的编程实现。 Spring JDBC:Java数据库连接。 Spring JMS:Java消息服务。 Spring ORM:用于支持Hibernate等ORM工具。 Spring Web:为创建Web应用程序提供支持。 Spring Test:提供了对JUnit和TestNG测试的支持。 谈谈自己对于Spring IOC和AOP的理解 IOC(Inversion Of Controll,控制反转)是一种设计思想: 在程序中手动创建对象的控制权,交由给Spring框架来管理。IOC在其他语言中也有应用,并非Spring特有。IOC容器实际上就是一个Map(key, value),Map中存放的是各种对象。 将对象之间的相互依赖关系交给IOC容器来管理,并由IOC容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。IOC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。在实际项目中一个Service类可能由几百甚至上千个类作为它的底层,假如我们需要实例化这个Service,可能要每次都搞清楚这个Service所有底层类的构造函数,这可能会把人逼疯。如果利用IOC的话,你只需要配置好,然后在需要的地方引用就行了,大大增加了项目的可维护性且降低了开发难度。 Spring中的bean的作用域有哪些? 1.singleton:该bean实例为单例 2.prototype:每次请求都会创建一个新的bean实例(多例)。 3.request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。 4.session:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP session内有效。 5.global-session:全局session作用域,仅仅在基于Portlet的Web应用中才有意义,Spring5中已经没有了。Portlet是能够生成语义代码(例如HTML)片段的小型Java Web插件。它们基于Portlet容器,可以像Servlet一样处理HTTP请求。但是与Servlet不同,每个Portlet都有不同的会话。 Spring中的单例bean的线程安全问题了解吗? 概念用于理解:大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例bean存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。 有两种常见的解决方案(用于回答的点): 1.在bean对象中尽量避免定义可变的成员变量(不太现实)。 2.在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal(线程本地化对象)中(推荐的一种方式)。 ThreadLocal解决多线程变量共享问题(参考博客):https://segmentfault.com/a/1190000009236777 Spring中Bean的生命周期: 1.Bean容器找到配置文件中Spring Bean的定义。 2.Bean容器利用Java Reflection API创建一个Bean的实例。 3.如果涉及到一些属性值,利用set方法设置一些属性值。 4.如果Bean实现了BeanNameAware接口,调用setBeanName方法,传入Bean的名字。 5.如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader方法,传入ClassLoader对象的实例。 6.如果Bean实现了BeanFactoryAware接口,调用setBeanClassFacotory方法,传入ClassLoader对象的实例。 7.与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。 8.如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执postProcessBeforeInitialization方法。 9.如果Bean实现了InitializingBean接口,执行afeterPropertiesSet方法。 10.如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。 11.如果有和加载这个Bean的Spring容器相关的BeanPostProcess对象,执行postProcessAfterInitialization方法。 12.当要销毁Bean的时候,如果Bean实现了DisposableBean接口,执行destroy方法。 13.当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。 Spring框架中用到了哪些设计模式? 1.工厂设计模式:Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对象。 2.代理设计模式:Spring AOP功能的实现。 3.单例设计模式:Spring中的bean默认都是单例的。 4.模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到了模板模式。 5.包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。 6.观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。 7.适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式、Spring MVC中也是用到了适配器模式适配Controller。 还有很多。。。。。。。 @Component和@Bean的区别是什么 1.作用对象不同。@Component注解作用于类,而@Bean注解作用于方法。 2.@Component注解通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用@ComponentScan注解定义要扫描的路径)。@Bean注解通常是在标有该注解的方法中定义产生这个bean,告诉Spring这是某个类的实例,当我需要用它的时候还给我。 3.@Bean注解比@Component注解的自定义性更强,而且很多地方只能通过@Bean注解来注册bean。比如当引用第三方库的类需要装配到Spring容器的时候,就只能通过@Bean注解来实现。 @Configuration public class AppConfig { @Bean public TransferService transferService { return new TransferServiceImpl; } } <beans> <bean id="transferService" class="com.kk.TransferServiceImpl"/> </beans> @Bean public OneService getService(status) { case (status) { when 1: return new serviceImpl1; when 2: return new serviceImpl2; when 3: return new serviceImpl3; } } 将一个类声明为Spring的bean的注解有哪些? 声明bean的注解: @Component 组件,没有明确的角色 @Service 在业务逻辑层使用(service层) @Repository 在数据访问层使用(dao层) @Controller 在展现层使用,控制器的声明 注入bean的注解: @Autowired:由Spring提供 @Inject:由JSR-330提供 @Resource:由JSR-250提供 *扩:JSR 是 java 规范标准 Spring事务管理的方式有几种? 1.编程式事务:在代码中硬编码(不推荐使用)。 2.声明式事务:在配置文件中配置(推荐使用),分为基于XML的声明式事务和基于注解的声明式事务。 Spring事务中的隔离级别有哪几种? 在TransactionDefinition接口中定义了五个表示隔离级别的常量:ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 Spring事务中有哪几种事务传播行为? 在TransactionDefinition接口中定义了八个表示事务传播行为的常量。 支持当前事务的情况:PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)。 不支持当前事务的情况:PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。 其他情况:PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED。 二、SpringMVC篇 什么是Spring MVC ?简单介绍下你对springMVC的理解? Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。 Spring MVC的工作原理了解嘛? image.png Springmvc的优点: (1)可以支持各种视图技术,而不仅仅局限于JSP; (2)与Spring框架集成(如IoC容器、AOP等); (3)清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。 (4) 支持各种请求资源的映射策略。 Spring MVC的主要组件? (1)前端控制器 DispatcherServlet(不需要程序员开发) 作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。 (2)处理器映射器HandlerMapping(不需要程序员开发) 作用:根据请求的URL来查找Handler (3)处理器适配器HandlerAdapter 注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。 (4)处理器Handler(需要程序员开发) (5)视图解析器 ViewResolver(不需要程序员开发) 作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view) (6)视图View(需要程序员开发jsp) View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等) springMVC和struts2的区别有哪些? (1)springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器(StrutsPrepareAndExecuteFilter)。 (2)springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。 (3)Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。 SpringMVC怎么样设定重定向和转发的? (1)转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4" (2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com" SpringMvc怎么和AJAX相互调用的? 通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。具体步骤如下 : (1)加入Jackson.jar (2)在配置文件中配置json的映射 (3)在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。 如何解决POST请求中文乱码问题,GET的又如何处理呢? (1)解决post请求乱码问题: 在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8; <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> (2)get请求中文参数出现乱码解决方法有两个: ①修改tomcat配置文件添加编码与工程编码一致,如下: <ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/> ②另外一种方法对参数进行重新编码: String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8") ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。 Spring MVC的异常处理 ? 统一异常处理: Spring MVC处理异常有3种方式: (1)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver; (2)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器; (3)使用@ExceptionHandler注解实现异常处理; 统一异常处理的博客:https://blog.csdn.net/ctwy291314/article/details/81983103 SpringMVC的控制器是不是单例模式,如果是,有什么问题,怎么解决? 是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写成员变量。(此题目类似于上面Spring 中 第5题 有两种解决方案) SpringMVC常用的注解有哪些? @RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。 @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。 @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。 SpingMvc中的控制器的注解一般用那个,有没有别的注解可以替代? 一般用@Controller注解,也可以使用@RestController,@RestController注解相当于@ResponseBody + @Controller,表示是表现层,除此之外,一般不用别的注解代替。 如果在拦截请求中,我想拦截get方式提交的方法,怎么配置? 可以在@RequestMapping注解里面加上method=RequestMethod.GET。 怎样在方法里面得到Request,或者Session? 直接在方法的形参中声明request,SpringMVC就自动把request对象传入。 如果想在拦截的方法里面得到从前台传入的参数,怎么得到? 直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样。 如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象? 直接在方法中声明这个对象,SpringMVC就自动会把属性赋值到这个对象里面。 SpringMVC中函数的返回值是什么? 返回值可以有很多类型,有String, ModelAndView。ModelAndView类把视图和数据都合并的一起的。 SpringMVC用什么对象从后台向前台传递数据的? 通过ModelMap对象,可以在这个对象里面调用put方法,把对象加到里面,前台就可以拿到数据。 怎么样把ModelMap里面的数据放入Session里面? 可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key。 SpringMvc里面拦截器是怎么写的: 有两种写法,一种是实现HandlerInterceptor接口,另外一种是继承适配器类,接着在接口方法当中,实现处理逻辑;然后在SpringMvc的配置文件中配置拦截器即可: <!-- 配置SpringMvc的拦截器 --> <mvc:interceptors> <!-- 配置一个拦截器的Bean就可以了 默认是对所有请求都拦截 --> <bean id="myInterceptor" class="com.zwp.action.MyHandlerInterceptor"></bean> <!-- 只针对部分请求拦截 --> <mvc:interceptor> <mvc:mapping path="/modelMap.do" /> <bean class="com.zwp.action.MyHandlerInterceptorAdapter" /> </mvc:interceptor> </mvc:interceptors> 注解原理: 注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池 三、Mybatis篇 什么是MyBatis? MyBatis是一个可以自定义SQL、存储过程和高级映射的持久层框架。 讲下MyBatis的缓存 MyBatis的缓存分为一级缓存和二级缓存,一级缓存放在session里面,默认就有, 二级缓存放在它的命名空间里,默认是不打开的,使用二级缓存属性类需要实现Serializable序列化接口, 可在它的映射文件中配置<cache/> Mybatis是如何进行分页的?分页插件的原理是什么? 1)Mybatis使用RowBounds对象进行分页,也可以直接编写sql实现分页,也可以使用Mybatis的分页插件。 2)分页插件的原理:实现Mybatis提供的接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql。 举例:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10 简述Mybatis的插件运行原理,以及如何编写一个插件? 1)Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、 Executor这4种接口的插件,Mybatis通过动态代理, 为需要拦截的接口生成代理对象以实现接口方法拦截功能, 每当执行这4种接口对象的方法时,就会进入拦截方法, 具体就是InvocationHandler的invoke方法,当然, 只会拦截那些你指定需要拦截的方法。 2)实现Mybatis的Interceptor接口并复写intercept方法, 然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可, 记住,别忘了在配置文件中配置你编写的插件。 Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不? 1)Mybatis动态sql可以让我们在Xml映射文件内, 以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。 2)Mybatis提供了9种动态sql标签:trim|where|set|foreach|if|choose|when|otherwise|bind。 3)其执行原理为,使用OGNL从sql参数对象中计算表达式的值, 根据表达式的值动态拼接sql,以此来完成动态sql的功能。 #{}和${}的区别是什么? 1)#{}是预编译处理,${}是字符串替换。 2)Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值(有效的防止SQL注入); 3)Mybatis在处理${}时,就是把${}替换成变量的值。 为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里? Hibernate属于全自动ORM映射工具, 使用Hibernate查询关联对象或者关联集合对象时, 可以根据对象关系模型直接获取,所以它是全自动的。 而Mybatis在查询关联对象或关联集合对象时, 需要手动编写sql来完成,所以,称之为半自动ORM映射工具。 Mybatis是否支持延迟加载?如果支持,它的实现原理是什么? 1)Mybatis仅支持association关联对象和collection关联集合对象的延迟加载, association指的就是一对一,collection指的就是一对多查询。 在Mybatis配置文件中, 可以配置是否启用延迟加载lazyLoadingEnabled=true|false。 2)它的原理是,使用CGLIB创建目标对象的代理对象, 当调用目标方法时,进入拦截器方法, 比如调用a.getB.getName, 拦截器invoke方法发现a.getB是null值, 那么就会单独发送事先保存好的查询关联B对象的sql, 把B查询上来,然后调用a.setB(b), 于是a的对象b属性就有值了, 接着完成a.getB.getName方法的调用。 这就是延迟加载的基本原理。 MyBatis与Hibernate有哪些不同? 1)Mybatis和hibernate不同,它不完全是一个ORM框架, 因为MyBatis需要程序员自己编写Sql语句, 不过mybatis可以通过XML或注解方式灵活配置要运行的sql语句, 并将java对象和sql语句映射生成最终执行的sql, 最后将sql执行的结果再映射生成java对象。 2)Mybatis学习门槛低,简单易学,程序员直接编写原生态sql, 可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发, 例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁, 一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性, 如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。 3)Hibernate对象/关系映射能力强,数据库无关性好, 对于关系模型要求高的软件(例如需求固定的定制化软件) 如果用hibernate开发可以节省很多代码,提高效率。 但是Hibernate的缺点是学习门槛高,要精通门槛更高, 而且怎么设计O/R映射,在性能和对象模型之间如何权衡, 以及怎样用好Hibernate需要具有很强的经验和能力才行。 总之,按照用户的需求在有限的资源环境下只要能做出维护性、 扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。 MyBatis的好处是什么? 1)MyBatis把sql语句从Java源程序中独立出来,放在单独的XML文件中编写, 给程序的维护带来了很大便利。 2)MyBatis封装了底层JDBC API的调用细节,并能自动将结果集转换成Java Bean对象, 大大简化了Java数据库编程的重复工作。 3)因为MyBatis需要程序员自己去编写sql语句, 程序员可以结合数据库自身的特点灵活控制sql语句, 因此能够实现比Hibernate等全自动orm框架更高的查询效率,能够完成复杂查询。 简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系? Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部。 在Xml映射文件中,<parameterMap>标签会被解析为ParameterMap对象, 其每个子元素会被解析为ParameterMapping对象。 <resultMap>标签会被解析为ResultMap对象, 其每个子元素会被解析为ResultMapping对象。 每一个<select>、<insert>、<update>、<delete> 标签均会被解析为MappedStatement对象, 标签内的sql会被解析为BoundSql对象。 什么是MyBatis的接口绑定,有什么好处? 接口映射就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定, 我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置. 接口绑定有几种实现方式,分别是怎么实现的? 接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加 上@Select@Update等注解里面包含Sql语句来绑定, 另外一种就是通过xml里面写SQL来绑定,在这种情况下, 要指定xml映射文件里面的namespace必须为接口的全路径名. 什么情况下用注解绑定,什么情况下用xml绑定? 当Sql语句比较简单时候,用注解绑定;当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多 MyBatis实现一对一有几种方式?具体怎么操作的? 有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次, 通过在resultMap里面配置association节点配置一对一的类就可以完成; 嵌套查询是先查一个表,根据这个表里面的结果的外键id, 去再另外一个表里面查询数据,也是通过association配置, 但另外一个表的查询通过select属性配置。 Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别? 能,Mybatis不仅可以执行一对一、一对多的关联查询, 还可以执行多对一,多对多的关联查询,多对一查询, 其实就是一对一查询,只需要把selectOne修改为selectList即可; 多对多查询,其实就是一对多查询,只需要把selectOne修改为selectList即可。 关联对象查询,有两种实现方式,一种是单独发送一个sql去查询关联对象, 赋给主对象,然后返回主对象。另一种是使用嵌套查询,嵌套查询的含义为使用join查询, 一部分列是A对象的属性值,另外一部分列是关联对象B的属性值, 好处是只发一个sql查询,就可以把主对象和其关联对象查出来。 MyBatis里面的动态Sql是怎么设定的?用什么语法? MyBatis里面的动态Sql一般是通过if节点来实现,通过OGNL语法来实现, 但是如果要写的完整,必须配合where,trim节点,where节点是判断包含节点有 内容就插入where,否则不插入,trim节点是用来判断如果动态语句是以and 或or 开始,那么会自动把这个and或者or取掉。 Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式? 第一种是使用<resultMap>标签,逐一定义列名和对象属性名之间的映射关系。 第二种是使用sql列的别名功能,将列别名书写为对象属性名, 比如T_NAME AS NAME,对象属性名一般是name,小写, 但是列名不区分大小写,Mybatis会忽略列名大小写,
-
PSSH 并发远程同步连接工具的使用和介绍
-
NIO] NIO 三剑客之一 ByteBuffer 的介绍和使用NIO 三剑客之一 ByteBuffer 的介绍和使用
-
Linux shell 脚本:介绍和使用 bash(详细)
-
异步编程RxJava-介绍-前言 前段时间写了一篇对协程的一些理解,里面提到了不管是协程还是callback,本质上其实提供的是一种异步无阻塞的编程模式;并且介绍了java中对异步无阻赛这种编程模式的支持,主要提到了Future和CompletableFuture;之后有同学在下面留言提到了RxJava,刚好最近在看微服务设计这本书,里面提到了响应式扩展(Reactive extensions,Rx),而RxJava是Rx在JVM上的实现,所有打算对RxJava进一步了解。 RxJava简介 RxJava的官网地址:https://github.com/ReactiveX/RxJava, 其中对RxJava进行了一句话描述:RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM. 大意就是:一个在Java VM上使用可观测的序列来组成异步的、基于事件的程序的库。 更详细的说明在Netflix技术博客的一篇文章中描述了RxJava的主要特点: 1.易于并发从而更好的利用服务器的能力。 2.易于有条件的异步执行。 3.一种更好的方式来避免回调地狱。 4.一种响应式方法。 与CompletableFuture对比 之前提到CompletableFuture真正的实现了异步的编程模式,一个比较常见的使用场景: CompletableFuture<Integer> future = CompletableFuture.supplyAsync(耗时函数); Future<Integer> f = future.whenComplete((v, e) -> { System.out.println(v); System.out.println(e); }); System.out.println("other..."); 下面用一个简单的例子来看一下RxJava是如何实现异步的编程模式: Observable<Long> observable = Observable.just(1, 2) .subscribeOn(Schedulers.io).map(new Func1<Integer, Long> { @Override public Long call(Integer t) { try { Thread.sleep(1000); //耗时的操作 } catch (InterruptedException e) { e.printStackTrace; } return (long) (t * 2); } }); observable.subscribe(new Subscriber<Long> { @Override public void onCompleted { System.out.println("onCompleted"); } @Override public void onError(Throwable e) { System.out.println("error" + e); } @Override public void onNext(Long result) { System.out.println("result = " + result); } }); System.out.println("other..."); Func1中以异步的方式执行了一个耗时的操作,Subscriber(观察者)被订阅到Observable(被观察者)中,当耗时操作执行完会回调Subscriber中的onNext方法。 其中的异步方式是在subscribeOn(Schedulers.io)中指定的,Schedulers.io可以理解为每次执行耗时操作都启动一个新的线程。 结构上其实和CompletableFuture很像,都是异步的执行一个耗时的操作,然后在有结果的时候主动告诉我结果。那我们还需要RxJava干嘛,不知道你有没有注意,上面的例子中其实提供2条数据流[1,2],并且处理完任何一个都会主动告诉我,当然这只是它其中的一项功能,RxJava还有很多好用的功能,在下面的内容会进行介绍。 异步观察者模式 上面这段代码有没有发现特别像设计模式中的:观察者模式;首先提供一个被观察者Observable,然后把观察者Subscriber添加到了被观察者列表中; RxJava中一共提供了四种角色:Observable、Observer、Subscriber、Subjects Observables和Subjects是两个被观察者,Observers和Subscribers是观察者; 当然我们也可以查看一下源码,看一下jdk中的Observer和RxJava的Observer jdk中的Observer: public interface Observer { void update(Observable o, Object arg); } RxJava的Observer: public interface Observer<T> { void onCompleted; void onError(Throwable e); void onNext(T t); } 同时可以发现Subscriber是implements Observer的: public abstract class Subscriber<T> implements Observer<T>, Subscription 可以发现RxJava中在Observer中引入了2个新的方法:onCompleted和onError onCompleted:即通知观察者Observable没有更多的数据,事件队列完结 onError:在事件处理过程中出异常时,onError会被触发,同时队列自动终止,不允许再有事件发出。 正是因为RxJava提供了同步和异步两种方式进行事件的处理,个人觉得异步的方式更能体现RxJava的价值,所以这里给他命名为异步观察者模式。 好了,下面正式介绍RxJava的那些灵活的操作符,这里仅仅是简单的介绍和简单的实例,具体用在什么场景下,会在以后的文章中介绍 Maven引入
-
Jar 包常用反编译工具介绍和使用
-
JDAX-GUI 反编译工具下载和使用及相关技术介绍