返回首页

gbase数据、南大通用产品文档:GBase8c查询最耗性能的SQL

更新日期:2024年09月11日

系统中有些SQL 语句运行了很长时间还没有结束,这些语句会消耗很多的系统性能,
请根据本章内容查询长时间运行的SQL 语句。
操作步骤

GBase 8c V5 开发者手册
南大通用数据技术股份有限公司
519
(1)
以操作系统用户gbase 登录数据库节点。
(2)
使用如下命令连接数据库。
gsql -d postgres -p 15432
postgres 为需要连接的数据库名称,15432 为数据库节点的端口号。
连接成功后,系统显示类似如下信息:
gsql ((GBase8c 3.0.0BXX build d28887c9) compiled at 2022-05-13 11:31:40 commit 0 last mr
55 )
Non-SSL connection (SSL connection is recommended when requiring high-security)
Type "help" for help.
gsql=#
(3)
查询系统中长时间运行的查询语句。
SELECT current_timestamp - query_start AS runtime, datname, usename, query FROM
pg_stat_activity where state != 'idle' ORDER BY 1 desc;
查询后会按执行时间从长到短顺序返回查询语句列表,
第一条结果就是当前系统中执行
时间最长的查询语句。返回结果中包含了系统调用的SQL 语句和用户执行SQL 语句,请根
据实际找到用户执行时间长的语句。
若当前系统较为繁忙,可以通过限制current_timestamp - query_start 大于某一阈值来查
看执行时间超过此阈值的查询语句。
SELECT query FROM pg_stat_activity WHERE current_timestamp - query_start > interval '1
days';
(4)
设置参数track_activities 为on。
SET track_activities = on;
当此参数为on 时,数据库系统才会收集当前活动查询的运行信息。
(5)
查看正在运行的查询语句。
以查看视图pg_stat_activity 为例:
SELECT datname, usename, state FROM pg_stat_activity;
datname
| usename | state
|
----------+---------+--------+
postgres |
gbase
| idle
|
postgres |
gbase
| active |
(2 rows)

GBase 8c V5 开发者手册
南大通用数据技术股份有限公司
520
如果state 字段显示为idle,则表明此连接处于空闲,等待用户输入命令。
如果仅需要查看非空闲的查询语句,则使用如下命令查看:
SELECT datname, usename, state FROM pg_stat_activity WHERE state != 'idle';
(6)
分析长时间运行的查询语句状态。
若查询语句处于正常状态,则等待其执行完毕。
若查询语句阻塞,则通过如下命令查看当前处于阻塞状态的查询语句:
SELECT datname, usename, state, query FROM pg_stat_activity WHERE waiting = true;
查询结果中包含了当前被阻塞的查询语句,
该查询语句所请求的锁资源可能被其他会话
持有,正在等待持有会话释放锁资源。
只有当查询阻塞在系统内部锁资源时,
waiting 字段才显示为true。
尽管等待锁资源是数
据库系统最常见的阻塞行为,但是在某些场景下查询也会阻塞在等待其他系统资源上,
例如写文件、
定时器等。
但是这种情况的查询阻塞,
不会在视图pg_stat_activity 中体现。

本节描述嵌套在另一 SELECT 语句的 WHERE 子句中的 SELECT 语句发生的子查询。
可以将任何关系运算符与 ALL 和 ANY 配合使用来将一些内容与子查询生成的值的每一

(ALL)
或任一个
(ANY)
进行比较。
可以使用关键字 SOME 代替 ANY。
运算符 IN 等
价于 = ANY。要创建相反的搜索条件,使用关键字 NOT 或另一个关系运算符。
EXISTS 运算符对子查询进行测试以了解子查询是否找到了任何值。即,该运算符询问子
查询的结果是否非空。不能在包含具有 TEXT 或 BYTE 数据类型的列的子查询中使用
EXISTS 关键字。
有关用于创建带子查询的条件的语法,请参阅《GBase 8s SQL 指南:语法》。
下列关键字介绍了 SELECT 语句的 WHERE 子句中的子查询。

ALL 关键字
在子查询前面使用 ALL 关键字来确定对返回的每个值的比较是否为 true。如果子查询不
返回任何值,那么搜索条件为 true。(如果子查询不返回任何值,那么对于所有零值条件
为 true 。)
下列查询列出了包含总价小于订单号 1023 中每个商品的总价的商品的所有订单的以下信
息。
图: 查询
SELECT order_num, stock_num, manu_code, total_price
FROM items
WHERE total_price < ALL
(SELECT total_price FROM items
WHERE order_num = 1023);
图: 查询结果
order_num stock_num manu_code total_price

GBase 8s SQL 指南:教程
南大通用数据技术股份有限公司 - 135 -


1003 9 ANZ $20.00
1005 6 SMT $36.00
1006 6 SMT $36.00
1010 6 SMT $36.00
1013 5 ANZ $19.80
1013 6 SMT $36.00
1018 302 KAR $15.00

ANY 关键字
在子查询前面使用关键字 ANY (或它的同义词 SOME)来确定是否对至少一个返回值的
比较为 true 。如果子查询不返回任何值,那么搜索条件为false。(因为没有值存在,所以
对于其中一个值条件不能为 true 。)
以下查询查找包含总价大于订单号 1005 中任何一个商品总价的商品的所有订单的订单
号。
图: 查询
SELECT DISTINCT order_num
FROM items
WHERE total_price > ANY
(SELECT total_price
FROM items
WHERE order_num = 1005);
图: 查询结果
order_num

1001
1002
1003
1004

1020
1021
1022
1023


GBase 8s SQL 指南:教程
南大通用数据技术股份有限公司 - 136 -

单值子查询
如果您知道子查询可能对外部级别查询返回刚好一个值,那么不需要 ALL 或 ANY 。可
如同对待函数一样对待只返回一个值的子查询。这种子查询通常使用聚集函数,原因是聚
集函数总是返回单个的。
下列查询在子查询中使用聚集函数 MAX 查找包括最大排球网数目的订单的 order_num。
图: 查询
SELECT order_num FROM items
WHERE stock_num = 9
AND quantity =
(SELECT MAX (quantity)
FROM items
WHERE stock_num = 9);
图: 查询结果
order_num

1012
下列查询在子查询中使用聚集函数 MIN 选择总价高于最小价格 10 倍的商品。
图: 查询
SELECT order_num, stock_num, manu_code, total_price
FROM items x
WHERE total_price >
(SELECT 10 * MIN (total_price)
FROM items
WHERE order_num = x.order_num);
图: 查询结果
order_num stock_num manu_code total_price

1003 8 ANZ $840.00
1018 307 PRC $500.00
1018 110 PRC $236.00
1018 304 HRO $280.00

相关子查询

GBase 8s SQL 指南:教程
南大通用数据技术股份有限公司 - 137 -

相关子查询是引用不在其 FROM 子句中的列或表的子查询。该列可以在 Projection 子句
或 WHERE 子句中。
通常,相关子查询会降低性能。建议使用表名或表别名限制子查询中的列名。从而除去与
列所驻留的表相关的任何疑问。
下列查询是相关子查询的一个示例,它返回 orders 表中 10 个最近的装运日期的列表。它
在子查询之后加上 ORDER BY 子句以对结果进行排序,原因是(除在 FROM 子句以外)
您不能在子查询中包括 ORDER BY 。
图: 查询
SELECT po_num, ship_date FROM orders main
WHERE 10 >
(SELECT COUNT (DISTINCT ship_date)
FROM orders sub
WHERE sub.ship_date < main.ship_date)
AND ship_date IS NOT NULL
ORDER BY ship_date, po_num;
因为子查询产生的数取决于 main.ship_date(外部 SELECT 产生的一个值),所以该子查
询是相关的。因此,必须对外部查询考虑的每一行重新执行子查询。
该查询使用 COUNT 函数来将值返回到主查询。然后,ORDER BY 子句对数据进行排序。
查询找到并返回具有 10 个最新装运日期的 16 行,如下所示。
图: 查询结果
po_num ship_date

4745 06/21/1998
278701 06/29/1998
429Q 06/29/1998
8052 07/03/1998
B77897 07/03/1998
LZ230 07/06/1998
B77930 07/10/1998
PC6782 07/12/1998
DM354331 07/13/1998
S22942 07/13/1998
MA003 07/16/1998
W2286 07/16/1998
Z55709 07/16/1998
C3288 07/25/1998

GBase 8s SQL 指南:教程
南大通用数据技术股份有限公司 - 138 -

KF2961 07/30/1998
W9925 07/30/1998
如果对大型表使用相关子查询(如图 1),那么应对 ship_date 列建立索引以提高性能。否
则,此 SELECT 语句效率降低,原因是它对表的每一行执行一次子查询。有关建立索引和
性能问题的信息,请参阅《GBase 8s 管理员指南》 和 GBase 8s 性能指南 。
然而,不能在 FROM 子句中使用相关子查询,如下列无效示例所示:
SELECT item_num, stock_num FROM items,
(SELECT stock_num FROM catalog
WHERE stock_num = items.item_num) AS vtab;
该示例中的子查询具有错误 -24138:
ALL COLUMN REFERENCES IN A TABLE EXPRESSION MUST REFER
TO TABLES IN THE FROM CLAUSE OF THE TABLE EXPRESSION.
数据库服务器发出该错误的原因是子查询中的 items.item_num 列还出现在外部查询的
Projection 子句中,
但是内部查询的 FROM 子句仅指定catalog 表。
错误消息文本中的术语
表表达式指的是 FROM 子句中的子查询返回的列值或表达式集合。而在 FROM 子句中,
只有不相关子查询才是有效的。

EXISTS 关键字
关键字 EXISTS 也被称为存在限定符,因为仅当外部 SELECT(如下所示)找到至少一行
时,子查询才为 true 。
图: 查询
SELECT UNIQUE manu_name, lead_time
FROM manufact
WHERE EXISTS
(SELECT * FROM stock
WHERE description MATCHES '*shoe*'
AND manufact.manu_code = stock.manu_code);
通常可使用 EXISTS 来构造等价于使用 IN 的查询的查询。
下列查询使用 IN 谓词来构造
与上述返回相同结果的查询。
图: 查询
SELECT UNIQUE manu_name, lead_time
FROM stock, manufact
WHERE manufact.manu_code IN
(SELECT manu_code FROM stock
WHERE description MATCHES '*shoe*')

GBase 8s SQL 指南:教程
南大通用数据技术股份有限公司 - 139 -

AND stock.manu_code = manufact.manu_code;
图 1和图 2返回生产某种鞋的制造商以及预订产品的交付周期的行。
该结果显示了返回值。

图: 查询结果
manu_name lead_time

Anza 5
Hero 4
Karsten 21
Nikolus 8
ProCycle 9
Shimara 30
将关键字 NOT 添加至 IN 或 EXISTS 以创建与前面查询相反的搜索条件。也可以
用 !=ALL 代替 NOT IN。
下列查询显示了执行同一操作的两种方法。一种方法可能允许数据库服务器执行相对另一
种方法较少的工作,则会取决于数据库的设计和表的大小。要了解哪一种查询更好,使用
SET EXPLAIN 命令来获取查询计划的清单。在 GBase 8s 性能指南 和 GBase 8s SQL 指
南:语法 中讨论了 SET EXPLAIN。
图: 查询
SELECT customer_num, company FROM customer
WHERE customer_num NOT IN
(SELECT customer_num FROM orders
WHERE customer.customer_num = orders.customer_num);

SELECT customer_num, company FROM customer
WHERE NOT EXISTS
(SELECT * FROM orders
WHERE customer.customer_num = orders.customer_num);
查询中的每个语句返回下列行,这些行标识尚未下订单的客户。
图: 查询结果
customer_num company

102 Sports Spot
103 Phil's Sports
105 Los Altos Sports
107 Athletic Supplies

GBase 8s SQL 指南:教程
南大通用数据技术股份有限公司 - 140 -

108 Quinn's Sports
109 Sport Stuff
113 Sportstown
114 Sporting Place
118 Blue Ribbon Sports
125 Total Fitness Sports
128 Phoenix University
关键字 EXISTS 和 IN 用于称为相交的集合运算,
关键 NOT EXISTS 和 NOT IN 用于称
为差异的集合运算。这些概念在集合运算中讨论。
下列查询执行对 items 表的子查询来标识 stock 表中尚未预订的所有商品。
图: 查询
SELECT * FROM stock
WHERE NOT EXISTS
(SELECT * FROM items
WHERE stock.stock_num = items.stock_num
AND stock.manu_code = items.manu_code);
该查询返回以下行。
图: 查询结果
stock_num manu_code description unit_price unit unit_descr

101 PRC bicycle tires $88.00 box 4/box
102 SHM bicycle brakes $220.00 case 4 sets/case
102 PRC bicycle brakes $480.00 case 4 sets/case
105 PRC bicycle wheels $53.00 pair pair

312 HRO racer goggles $72.00 box 12/box
313 SHM swim cap $72.00 box 12/box
313 ANZ swim cap $60.00 box 12/box
对 SELECT 语句可具有的子查询数没有逻辑限制。
您可能想要检查是否在数据库中正确输入了信息。查找数据库中的错误的一种方法是编写
仅当错误存在时才会返回输出的查询。这种类型的子查询充当一种审计查询,如下所示。
图: 查询
SELECT * FROM items
WHERE total_price != quantity *
(SELECT unit_price FROM stock

GBase 8s SQL 指南:教程
南大通用数据技术股份有限公司 - 141 -

WHERE stock.stock_num = items.stock_num
AND stock.manu_code = items.manu_code);
该查询只返回订单上商品的总价格不等于库存单价乘以订单数量的行。如果没有应用任何
折扣,那么可能在数据库中不正确地输入了此类型的行。仅当错误发生时查询才会返回行。
如果正确地将信息插入到数据库中,那么不会返回任何行。
图: 查询结果
item_num order_num stock_num manu_code quantity total_price

1 1004 1 HRO 1 $960.00
2 1006 5 NRG 5 $190.00

使用 STMT_CACHE_SIZE 配置参数来指定以 KB 为单位的 SQL 语句高速缓存的大小。在下
一次添加语句到高速缓存时,新的高速缓存大小生效。
onconfig.std 值
STMT_CACHE_SIZE 512

正整数
单位
KB
生效
编辑 onconfig 文件并重启数据库服务器之后。