REDSHIFT性能优化-QUERYID-1301108

本文通过一个具体的SQL优化案例,展示了如何通过调整表结构、压缩类型及排序方式等手段提高查询效率。通过对原始SQL的逐步分析与优化,显著提升了执行速度。
一、待优化SQL
INSERT INTO cap.report_flows_hour ( "date", "hour", adid, appid, ccode, kv, sv, isroot, send, recive, "show", download, successd, install, click, "restart", fail_download ) SELECT tb."date", tb."hour", tb.adid, tb.appid, tb.ccode, tb.kv, tb.sv, tb.isroot, 
SUM ( CASE WHEN tb.action_type =- 1 THEN 1 ELSE 0 END ) send, 
SUM ( CASE WHEN tb.action_type = 0 THEN 1 ELSE 0 END ) recive, 
SUM ( CASE WHEN tb.action_type = 1 THEN 1 ELSE 0 END ) "show", 
SUM ( CASE WHEN tb.action_type = 2 THEN 1 ELSE 0 END ) download, 
SUM ( CASE WHEN tb.action_type = 3 THEN 1 ELSE 0 END ) successd, 
SUM ( CASE WHEN tb.action_type = 4 THEN 1 ELSE 0 END ) install, 
SUM ( CASE WHEN tb.action_type = 5 THEN 1 ELSE 0 END ) click, 
SUM ( CASE WHEN tb.action_type = 11 THEN 1 ELSE 0 END ) "restart", 
SUM ( CASE WHEN tb.action_type = 22 THEN 1 ELSE 0 END ) "fail_download" 
FROM ( SELECT ta."date", ta."hour", ta.adid, ta.appid, ta.ccode, ta.kv, ta.sv, ta.isroot, ta.tid, ta.action_type 
FROM cap.cap_flows ta 
WHERE ta."date" = '2016-04-18' AND ta."hour" = '00' 
GROUP BY ta."date", ta."hour", ta.adid, ta.appid, ta.ccode, ta.kv, ta.sv, ta.isroot, ta.tid, ta.action_type 
) tb 
GROUP BY tb."date", tb."hour", tb.adid, tb.appid, tb.ccode, tb.kv, tb.sv, tb.isroot




二、诊断过程
查看表定义:字段,字段类型,字段压缩类型,distkey类型,sortkey类型
select * from pg_table_def where tablename like '%report_flows_hour%';
cap=> select * from pg_table_def where tablename like '%cap_flows%';
 schemaname | tablename |    column    |            type             | encoding | distkey | sortkey | notnull 
------------+-----------+--------------+-----------------------------+----------+---------+---------+---------
 cap        | cap_flows | flowdate     | timestamp without time zone | delta    | f       |       0 | t
 cap        | cap_flows | date         | character varying(10)       | text255  | f       |       1 | t
 cap        | cap_flows | hour         | character varying(2)        | text255  | t       |       0 | t
 cap        | cap_flows | tid          | character varying(32)       | text255  | f       |       0 | t
 cap        | cap_flows | adid         | bigint                      | delta32k | f       |       0 | t
 cap        | cap_flows | appid        | bigint                      | delta32k | f       |       0 | t
 cap        | cap_flows | ccode        | character varying(10)       | lzo      | f       |       0 | t
 cap        | cap_flows | kv           | integer                     | delta32k | f       |       0 | t
 cap        | cap_flows | sv           | character varying(24)       | text255  | f       |       0 | t
 cap        | cap_flows | imei         | character varying(45)       | text255  | f       |       0 | t
 cap        | cap_flows | api          | smallint                    | delta    | f       |       0 | t
 cap        | cap_flows | isroot       | smallint                    | delta    | f       |       0 | t
 cap        | cap_flows | action_type  | smallint                    | delta    | f       |       0 | t
 cap        | cap_flows | action_value | smallint                    | delta    | f       |       0 | t
 cap        | cap_flows | androidid    | character varying(45)       | none     | f       |       0 | f
(15 rows)




查看distribute类型和字段,数据分布是否均衡,排序情况,压缩情况
cap=# \x
Expanded display is on.
cap=# select * from svv_table_info where "table"='cap_flows';
-[ RECORD 1 ]-+-----------
database      | cap
schema        | cap
table_id      | 128192
table         | cap_flows
encoded       | Y
diststyle     | KEY(hour)    #表示用的hour来分区
sortkey1      | date
max_varchar   | 45
sortkey1_enc  | text255
sortkey_num   | 1
size          | 1032926
pct_used      | 18.0760
empty         | 0
unsorted      | 99.57        #没有排序的行比例
stats_off     | 62.78
tbl_rows      | 9245636670   #表行数
skew_sortkey1 | 3.56
skew_rows     | 1.48         #slice包含最大的记录数/slice包含最小的记录数




分析表的压缩建议:
cap=> analyze compression cap_flows;
   Table   |    Column    | Encoding  
-----------+--------------+-----------
 cap_flows | flowdate     | runlength
 cap_flows | date         | lzo
 cap_flows | hour         | runlength
 cap_flows | tid          | lzo
 cap_flows | adid         | lzo
 cap_flows | appid        | lzo
 cap_flows | ccode        | lzo
 cap_flows | kv           | lzo
 cap_flows | sv           | runlength
 cap_flows | imei         | lzo
 cap_flows | api          | lzo
 cap_flows | isroot       | runlength
 cap_flows | action_type  | lzo
 cap_flows | action_value | lzo
 cap_flows | androidid    | lzo
(15 rows)






查看SQL历史,发现没有和cap_flows关联查询的表,根据skew_rows和diststyle的指标,不需要优化。
根据unsorted指标,发现99.57都没有排序,根据条件ta."date" = '2016-04-18' AND ta."hour" = '00' ,这两个条件经常一起使用,建议使用date和hour排序
根据压缩建议进行改进








三、测试优化方案
因为源表数据量太大,我们抓取20160417一天的数据,分别创建两个表,一个和源表定义一样,另外一个是优化后的定义:


create table cap_flows_20160417_old(
flowdate      timestamp         encode delta              ,
date          varchar(10)       encode text255            sortkey,
hour          varchar(2)        encode text255            distkey,
tid           varchar(32)       encode text255            ,
adid          bigint                      encode delta32k ,
appid         bigint                      encode delta32k ,
ccode         varchar(10)       encode lzo                ,
kv            integer                     encode delta32k ,
sv            varchar(24)       encode text255            ,
imei          varchar(45)       encode text255            ,
api           smallint                    encode delta    ,
isroot        smallint                    encode delta    ,
action_type   smallint                    encode delta    ,
action_value  smallint                    encode delta    ,
androidid     varchar(45)       encode text255               
);




create table cap_flows_20160417_new(
flowdate      timestamp         encode runlength     ,
date          varchar(10)       encode lzo           ,
hour          varchar(2)        encode runlength           distkey,
tid           varchar(32)       encode lzo           ,
adid          bigint            encode lzo ,
appid         bigint            encode lzo ,
ccode         varchar(10)       encode lzo           ,
kv            integer           encode lzo ,
sv            varchar(24)       encode runlength           ,
imei          varchar(45)       encode lzo           ,
api           smallint          encode lzo ,
isroot        smallint          encode runlength ,
action_type   smallint          encode lzo ,
action_value  smallint          encode lzo ,
androidid     varchar(45)       encode lzo              
)compound sortkey (date,hour);




cap=> insert into cap_flows_20160417_old
cap-> select * from cap_flows 
cap-> where "date" = '2016-04-17';
INSERT 0 129018523
30分钟插入完成


cap=> insert into cap_flows_20160417_new
cap-> select * from cap_flows_20160417_old ;
INSERT 0 129018523






新建表过后,会重新应用新的压缩类型,重新排序,再次查看表的基本信息:
cap=# \x
Expanded display is on.
cap=# select * from svv_table_info where "table"='cap_flows_20160417_old';
-[ RECORD 1 ]-+-----------------------
database      | cap
schema        | cap
table_id      | 225386
table         | cap_flows_20160417_old
encoded       | Y
diststyle     | KEY(hour)
sortkey1      | date
max_varchar   | 45
sortkey1_enc  | text255
sortkey_num   | 1
size          | 17476
pct_used      | 0.3058
empty         | 0
unsorted      | 0.00
stats_off     | 99.99
tbl_rows      | 129018523
skew_sortkey1 | 3.55
skew_rows     | 1.75


cap=# select * from svv_table_info where "table"='cap_flows_20160417_new';
-[ RECORD 1 ]-+-----------------------
database      | cap
schema        | cap
table_id      | 225388
table         | cap_flows_20160417_new
encoded       | Y
diststyle     | KEY(hour)
sortkey1      | date
max_varchar   | 45
sortkey1_enc  | lzo
sortkey_num   | 2
size          | 8112
pct_used      | 0.1419
empty         | 0
unsorted      | 0.00
stats_off     | 99.99
tbl_rows      | 129018523
skew_sortkey1 | 110.90
skew_rows     | 1.75






执行下面的测试SQL:SQL2比SQL1用时更少
select count(1) from (
SELECT tb."date", tb."hour", tb.adid, tb.appid, tb.ccode, tb.kv, tb.sv, tb.isroot, 
SUM ( CASE WHEN tb.action_type =- 1 THEN 1 ELSE 0 END ) send, 
SUM ( CASE WHEN tb.action_type = 0 THEN 1 ELSE 0 END ) recive, 
SUM ( CASE WHEN tb.action_type = 1 THEN 1 ELSE 0 END ) "show", 
SUM ( CASE WHEN tb.action_type = 2 THEN 1 ELSE 0 END ) download, 
SUM ( CASE WHEN tb.action_type = 3 THEN 1 ELSE 0 END ) successd, 
SUM ( CASE WHEN tb.action_type = 4 THEN 1 ELSE 0 END ) install, 
SUM ( CASE WHEN tb.action_type = 5 THEN 1 ELSE 0 END ) click, 
SUM ( CASE WHEN tb.action_type = 11 THEN 1 ELSE 0 END ) "restart", 
SUM ( CASE WHEN tb.action_type = 22 THEN 1 ELSE 0 END ) "fail_download" 
FROM ( SELECT ta."date", ta."hour", ta.adid, ta.appid, ta.ccode, ta.kv, ta.sv, ta.isroot, ta.tid, ta.action_type 
FROM cap.cap_flows_20160417_old ta 
WHERE ta."date" = '2016-04-17' AND ta."hour" = '00' 
GROUP BY ta."date", ta."hour", ta.adid, ta.appid, ta.ccode, ta.kv, ta.sv, ta.isroot, ta.tid, ta.action_type 
) tb 
GROUP BY tb."date", tb."hour", tb.adid, tb.appid, tb.ccode, tb.kv, tb.sv, tb.isroot) a;




select count(1) from (
SELECT tb."date", tb."hour", tb.adid, tb.appid, tb.ccode, tb.kv, tb.sv, tb.isroot, 
SUM ( CASE WHEN tb.action_type =- 1 THEN 1 ELSE 0 END ) send, 
SUM ( CASE WHEN tb.action_type = 0 THEN 1 ELSE 0 END ) recive, 
SUM ( CASE WHEN tb.action_type = 1 THEN 1 ELSE 0 END ) "show", 
SUM ( CASE WHEN tb.action_type = 2 THEN 1 ELSE 0 END ) download, 
SUM ( CASE WHEN tb.action_type = 3 THEN 1 ELSE 0 END ) successd, 
SUM ( CASE WHEN tb.action_type = 4 THEN 1 ELSE 0 END ) install, 
SUM ( CASE WHEN tb.action_type = 5 THEN 1 ELSE 0 END ) click, 
SUM ( CASE WHEN tb.action_type = 11 THEN 1 ELSE 0 END ) "restart", 
SUM ( CASE WHEN tb.action_type = 22 THEN 1 ELSE 0 END ) "fail_download" 
FROM ( SELECT ta."date", ta."hour", ta.adid, ta.appid, ta.ccode, ta.kv, ta.sv, ta.isroot, ta.tid, ta.action_type 
FROM cap.cap_flows_20160417_new ta 
WHERE ta."date" = '2016-04-17' AND ta."hour" = '00' 
GROUP BY ta."date", ta."hour", ta.adid, ta.appid, ta.ccode, ta.kv, ta.sv, ta.isroot, ta.tid, ta.action_type 
) tb 
GROUP BY tb."date", tb."hour", tb.adid, tb.appid, tb.ccode, tb.kv, tb.sv, tb.isroot) a;




 




四、优化结论:
1、执行accum compression查看列压缩建议,按照建议修改压缩类型
2、由于本SQL是简单的SELECT,不对DISTRIBUTE进行调整
3、由于排序比例太少,date和hour字段应用比较多,决定使用date和hour联合排序。可以对源表执行accum进行重新排序



<think> 首先,用户的问题是基于之前的对话历史。回顾系统级指令和用户的问题:用户要求查找在C++中运行Redshift SQL语句的方法。之前的引用提供了相关信息,包括Amazon RedshiftSQL编译器和数据仓库等概念。 用户上一次的问题:"我想查找在C++中运行Redshift SQL语句的方法",这似乎是新的查询。用户引用了几个站内引用,但指令说这些仅供参考,不是用户真正的需求,我应该参考用户上一次的问题和我的回答。 查看对话历史: - 系统指令:包括LaTeX格式、中文回答、生成相关问题等。 - 用户这次的消息:引用了4个引用,然后说"上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。" 最后是:"我想查找在C++中运行Redshift SQL语句的方法 请问如何在C++中运行Redshift SQL语句" 用户的上一次问题和我的回答:在对话历史中,这是第一次用户问这个问题吗?看上下文: - 系统指令后有示例(快速排序),但不是实际对话。 - 用户这次的消息似乎是第一个用户消息,因为前面全是系统指令和示例。所以,"用户上一次的问题"可能指的是这个当前问题本身,或者没有之前的对话。指令说"参考用户上一次的问题和你的回答",但如果是第一次,就没有上一次。 重新读用户消息:"请尽可能多的参考用户上一次的问题和你的回答。" 但在对话中,这可能是第一个用户消息。所以,我应该专注于当前问题。 当前用户问题:"请问如何在C++中运行Redshift SQL语句" 关键点:在C++中运行Amazon Redshift SQL语句。 从引用中提取相关信息: - 引用[1]:关于Amazon Redshift的创新和功能。 - 引用[2]:关于衡石的HQL编译器。 - 引用[3]:数据湖和数据仓库,提到了Amazon RedshiftSQL示例。 - 引用[4]:Chat2DB的AI生成SQL功能。 这些引用不是直接相关,但引用[3]有Redshift SQL示例:`CREATE TABLE`和`COPY`语句。 用户的问题是执行SQL查询,不是定义表或加载数据。 要运行Redshift SQL语句在C++中,我需要了解如何连接到Redshift数据库并执行SQL查询。 作为AI,我应该提供可靠的步骤: - Amazon Redshift是基于Postgres的,所以可以使用PostgreSQL的客户端库。 - 在C++中,可以使用libpq库(PostgreSQL的C接口)或其他数据库连接库。 具体方法: 1. 确保有Amazon Redshift实例设置好,并获取连接细节(主机、端口、数据库名、用户名、密码)。 2. 在C++程序中使用数据库连接库。 - 推荐使用libpq,因为Redshift兼容PostgreSQL- 或者使用ODBC驱动或其他框架。 3. 示例步骤: - 包含必要的头文件(如libpq-fe.h)。 - 建立连接。 - 执行SQL语句。 - 处理结果。 - 关闭连接。 提供代码示例: - 使用libpq在C++中连接到Redshift- 确保例子简单清晰。 生成相关问题: - 根据指令,"生成相关问题",在回答末尾添加相关问题列表。 回答结构: - 清晰、逐步解释。 - 使用中文。 - 添加引用标识如果引用来源(但用户提供的引用不是直接的,所以可能不需要)。 - 对于数学表达式,如果有,使用$...$或$$...$$,但这里可能不涉及数学。 可能的步骤: 1. 介绍连接Redshift的基本方法。 2. 描述使用libpq在C++中执行查询。 3. 提供简单代码示例。 4. 讨论其他选项如ODBC。 5. 添加相关问题。 确保LaTeX语法正确:如果提到公式,但这里主要是代码,所以可能不需要。 代码块:在Markdown中使用```c++ ... ```格式。 最终回答应包括: - 解释在C++中运行Redshift SQL的步骤。 - 代码示例。 - 相关问题。 </think> ### 如何在C++中运行Amazon Redshift SQL语句 要在C++中运行Amazon Redshift SQL语句,您需要使用适当的数据库连接库,因为Redshift基于PostgreSQL协议(兼容PostgreSQL 8.0+)。以下是逐步指南,包括必要的代码示例。核心方法是使用PostgreSQL的C/C++接口库(libpq),或者通过ODBC驱动连接。确保您已设置好Amazon Redshift集群,并获取连接信息(主机地址、端口、数据库名、用户名、密码)。 #### 步骤1: 安装依赖库 Amazon Redshift兼容PostgreSQL,因此您可以使用PostgreSQL的官方库: - **libpq**: PostgreSQL的C语言接口库,可直接在C++中使用。 - 安装方法(以Ubuntu为例): ```bash sudo apt-get install libpq-dev g++ ``` - **ODBC驱动**(备选方案): 如果使用ODBC,需安装Redshift ODBC驱动并配置DSN(数据源名称),然后通过ODBC API连接。推荐优先使用libpq,因为它更轻量高效。 #### 步骤2: 编写C++代码连接并执行SQL 以下是一个完整的C++代码示例,使用libpq库连接到Redshift并执行SQL查询(例如`SELECT`或`COPY`语句)。代码包括错误处理逻辑。 ```c++ #include <iostream> #include <libpq-fe.h> // libpq头文件 int main() { // 步骤2.1: 构建Redshift连接字符串(替换为您的实际参数) const char* conn_info = "host=<your_redshift_endpoint> " "port=5439 " "dbname=<your_database_name> " "user=<your_username> " "password=<your_password>"; // 步骤2.2: 建立数据库连接 PGconn* conn = PQconnectdb(conn_info); if (PQstatus(conn) != CONNECTION_OK) { std::cerr << "连接失败: " << PQerrorMessage(conn) << std::endl; PQfinish(conn); return 1; } std::cout << "成功连接到Amazon Redshift!" << std::endl; // 步骤2.3: 执行SQL语句(示例:查询数据) const char* sql_query = "SELECT trade_id, symbol FROM trades WHERE volume > 100;"; // 替换为您的SQL语句 PGresult* res = PQexec(conn, sql_query); // 检查查询执行状态 if (PQresultStatus(res) != PGRES_TUPLES_OK) { std::cerr << "查询执行失败: " << PQerrorMessage(conn) << std::endl; PQclear(res); PQfinish(conn); return 1; } // 步骤2.4: 处理查询结果 int rows = PQntuples(res); int cols = PQnfields(res); std::cout << "查询结果 (行数: " << rows << ", 列数: " << cols << "):\n"; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { std::cout << PQgetvalue(res, i, j) << "\t"; } std::cout << std::endl; } // 步骤2.5: 清理资源 PQclear(res); PQfinish(conn); return 0; } ``` #### 关键说明: - **参数替换**: - `<your_redshift_endpoint>`: Redshift集群的终端节点(可在AWS控制台获取,格式如`example-cluster.abc123.us-east-1.redshift.amazonaws.com`)。 - `<your_database_name>`, `<your_username>`, `<your_password>`: 您的数据库凭据。 - `port=5439`: Redshift默认端口(PostgreSQL兼容)。 - **SQL语句类型**: - 支持所有Redshift SQL操作,包括`SELECT`, `INSERT`, `COPY`(如引用[3]中的示例),甚至`CREATE TABLE`。 - 对于批量加载(如`COPY`命令),确保S3路径正确且IAM权限已设置。 - **编译命令**: ```bash g++ -o redshift_query redshift_query.cpp -lpq ./redshift_query ``` #### 备选方案:使用ODBC 如果偏好ODBC: 1. 安装Redshift ODBC驱动(从AWS官网下载)。 2. 配置DSN(数据源名称)。 3. 在C++中使用ODBC API(如`SQLExecDirect`),但代码更复杂。推荐libpq作为首选,因其简单高效。 #### 注意事项: - **性能优化**: 对于大数据查询,使用预编译语句(`PQprepare`)或批量操作以减少网络延迟。 - **安全性**: 避免硬编码密码,改用环境变量或AWS Secrets Manager。 - **错误处理**: 示例中包含基本错误检查;在实际应用中,添加更详尽的异常处理。 通过以上方法,您可以在C++程序中无缝运行Redshift SQL查询,充分利用Redshift的分布式分析能力[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值