| --- |
| { |
| "title": "TPC-H Benchmark", |
| "language": "zh-CN" |
| } |
| --- |
| |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| |
| # TPC-H Benchmark |
| |
| TPC-H 是一个决策支持基准(Decision Support Benchmark),它由一套面向业务的特别查询和并发数据修改组成。查询和填充数据库的数据具有广泛的行业相关性。这个基准测试演示了检查大量数据、执行高度复杂的查询并回答关键业务问题的决策支持系统。TPC-H 报告的性能指标称为 TPC-H 每小时复合查询性能指标 (QphH@Size),反映了系统处理查询能力的多个方面。这些方面包括执行查询时所选择的数据库大小,由单个流提交查询时的查询处理能力,以及由多个并发用户提交查询时的查询吞吐量。 |
| |
| 本文档主要介绍 Doris 在 TPC-H 1000G 测试集上的性能表现。 |
| |
| 在 TPC-H 标准测试数据集上的 22 个查询上,我们基于 Apache Doris 2.1.1-rc03 和 Apache Doris 2.0.6 版本进行了对比测试。 |
| |
|  |
| |
| ## 1. 硬件环境 |
| |
| | 硬件 | 配置说明 | |
| |------|--------------------------------------| |
| | 机器数量 | 4 台腾讯云主机(1 个 FE,3 个 BE) | |
| | CPU | AMD EPYC™ Milan(2.55GHz/3.5GHz) 48 核 | |
| | 内存 | 192G | |
| | 网络带宽 | 21Gbps | |
| | 磁盘 | 高性能云硬盘 | |
| |
| ## 2. 软件环境 |
| |
| - Doris 部署 3BE 1FE |
| - 内核版本:Linux version 5.4.0-96-generic (buildd@lgw01-amd64-051) |
| - 操作系统版本:Ubuntu 20.04 LTS (Focal Fossa) |
| - Doris 软件版本:Apache Doris 2.1.1-rc03、Apache Doris 2.0.6 |
| - JDK:openjdk version "1.8.0_131" |
| |
| ## 3. 测试数据量 |
| |
| 整个测试模拟生成 TPCH 1000G 的数据分别导入到 Apache Doris 2.1.1-rc03 和 Apache Doris 2.0.6 版本进行测试,下面是表的相关说明及数据量。 |
| |
| | TPC-H 表名 | 行数 | 备注 | |
| |:---------|:------|:-------| |
| | REGION | 5 | 区域表 | |
| | NATION | 25 | 国家表 | |
| | SUPPLIER | 1000 万 | 供应商表 | |
| | PART | 2 亿 | 零部件表 | |
| | PARTSUPP | 8 亿 | 零部件供应表 | |
| | CUSTOMER | 1.5 亿 | 客户表 | |
| | ORDERS | 15 亿 | 订单表 | |
| | LINEITEM | 60 亿 | 订单明细表 | |
| |
| ## 4. 测试 SQL |
| |
| TPCH 22 个测试查询语句: [TPCH-Query-SQL](https://github.com/apache/doris/tree/master/tools/tpch-tools/queries/sf1000) |
| |
| |
| ## 5. 测试结果 |
| |
| 这里我们使用 Apache Doris 2.1.1-rc03 和 Apache Doris 2.0.6 版本进行对比测试,测试结果如下: |
| |
| | Query | Apache Doris 2.1.1-rc03 (ms) | Apache Doris 2.0.6 (ms) | |
| |--------|------------------------------|-------------------------| |
| | Q1 | 7240 | 7638 | |
| | Q2 | 249 | 377 | |
| | Q3 | 3528 | 4389 | |
| | Q4 | 1534 | 1903 | |
| | Q5 | 5457 | 6425 | |
| | Q6 | 159 | 150 | |
| | Q7 | 1598 | 3141 | |
| | Q8 | 2958 | 2792 | |
| | Q9 | 14803 | 24732 | |
| | Q10 | 6743 | 7315 | |
| | Q11 | 414 | 395 | |
| | Q12 | 371 | 417 | |
| | Q13 | 6203 | 8095 | |
| | Q14 | 485 | 681 | |
| | Q15 | 2246 | 1459 | |
| | Q16 | 1252 | 1382 | |
| | Q17 | 1461 | 1204 | |
| | Q18 | 10428 | 11386 | |
| | Q19 | 2329 | 2172 | |
| | Q20 | 569 | 1455 | |
| | Q21 | 5574 | 6570 | |
| | Q22 | 1042 | 1517 | |
| | **合计** | **76643** | **95595** | |
| |
| ## 6. 环境准备 |
| |
| 请先参照 [官方文档](../install/cluster-deployment/standard-deployment) 进行 Doris 的安装部署,以获得一个正常运行中的 Doris 集群(至少包含 1 FE 1 BE,推荐 1 FE 3 BE)。 |
| |
| ## 7. 数据准备 |
| |
| ### 7.1 下载安装 TPC-H 数据生成工具 |
| |
| 执行以下脚本下载并编译 [tpch-tools](https://github.com/apache/doris/tree/master/tools/tpch-tools) 工具。 |
| |
| ```shell |
| sh bin/build-tpch-dbgen.sh |
| ``` |
| |
| 安装成功后,将在 `TPC-H_Tools_v3.0.0/` 目录下生成 `dbgen` 二进制文件。 |
| |
| ### 7.2 生成 TPC-H 测试集 |
| |
| 执行以下脚本生成 TPC-H 数据集: |
| |
| ```shell |
| sh bin/gen-tpch-data.sh -s 1000 |
| ``` |
| |
| > 注 1:通过 `sh gen-tpch-data.sh -h` 查看脚本帮助。 |
| > |
| > 注 2:数据会以 `.tbl` 为后缀生成在 `tpch-data/` 目录下。文件总大小约 1000GB。生成时间可能在数分钟到 1 小时不等。 |
| > |
| > 注 3:默认生成 100G 的标准测试数据集 |
| |
| ### 7.3 建表 |
| |
| #### 7.3.1 准备 `doris-cluster.conf` 文件 |
| |
| 在调用导入脚本前,需要将 FE 的 ip 端口等信息写在 `doris-cluster.conf` 文件中。 |
| |
| 文件位置在 `${DORIS_HOME}/tools/tpch-tools/conf/` 目录下。 |
| |
| 文件内容包括 FE 的 ip,HTTP 端口,用户名,密码以及待导入数据的 DB 名称: |
| |
| ```shell |
| # Any of FE host |
| export FE_HOST='127.0.0.1' |
| # http_port in fe.conf |
| export FE_HTTP_PORT=8030 |
| # query_port in fe.conf |
| export FE_QUERY_PORT=9030 |
| # Doris username |
| export USER='root' |
| # Doris password |
| export PASSWORD='' |
| # The database where TPC-H tables located |
| export DB='tpch' |
| ``` |
| |
| #### 7.3.2 执行以下脚本生成创建 TPC-H 表 |
| |
| ```shell |
| sh bin/create-tpch-tables.sh -s 1000 |
| ``` |
| 或者复制 [create-tpch-tables.sql](https://github.com/apache/doris/blob/master/tools/tpch-tools/ddl/create-tpch-tables-sf1000.sql) 中的建表语句,在 Doris 中执行。 |
| |
| |
| ### 7.4 导入数据 |
| |
| 通过下面的命令执行数据导入: |
| |
| ```shell |
| sh bin/load-tpch-data.sh |
| ``` |
| |
| ### 7.5 检查导入数据 |
| |
| 执行下面的 SQL 语句检查导入的数据与上面的数据量一致。 |
| |
| ```sql |
| select count(*) from lineitem; |
| select count(*) from orders; |
| select count(*) from partsupp; |
| select count(*) from part; |
| select count(*) from customer; |
| select count(*) from supplier; |
| select count(*) from nation; |
| select count(*) from region; |
| select count(*) from revenue0; |
| ``` |
| |
| ### 7.6 查询测试 |
| |
| ### 7.6.1 执行查询脚本 |
| |
| 执行上面的测试 SQL 或者 执行下面的命令 |
| |
| ```shell |
| sh bin/run-tpch-queries.sh -s 1000 |
| ``` |
| |
| |
| ### 7.6.2 单个 SQL 执行 |
| |
| 下面是测试时使用的 SQL 语句,你也可以从代码库里获取最新的 SQL。最新测试查询语句地址:[TPC-H 测试查询语句](https://github.com/apache/doris/tree/master/tools/tpch-tools/queries/sf1000) |
| |
| ```sql |
| --Q1 |
| 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; |
| |
| --Q2 |
| 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 = 15 |
| and p_type like '%BRASS' |
| and s_nationkey = n_nationkey |
| and n_regionkey = r_regionkey |
| and r_name = 'EUROPE' |
| 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 = 'EUROPE' |
| ) |
| order by |
| s_acctbal desc, |
| n_name, |
| s_name, |
| p_partkey |
| limit 100; |
| |
| --Q3 |
| 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-15' |
| and l_shipdate > date '1995-03-15' |
| group by |
| l_orderkey, |
| o_orderdate, |
| o_shippriority |
| order by |
| revenue desc, |
| o_orderdate |
| limit 10; |
| |
| --Q4 |
| select |
| o_orderpriority, |
| count(*) as order_count |
| from |
| orders |
| where |
| o_orderdate >= date '1993-07-01' |
| and o_orderdate < date '1993-07-01' + interval '3' month |
| and exists ( |
| select |
| * |
| from |
| lineitem |
| where |
| l_orderkey = o_orderkey |
| and l_commitdate < l_receiptdate |
| ) |
| group by |
| o_orderpriority |
| order by |
| o_orderpriority; |
| |
| --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 = 'ASIA' |
| and o_orderdate >= date '1994-01-01' |
| and o_orderdate < date '1994-01-01' + interval '1' year |
| group by |
| n_name |
| order by |
| revenue desc; |
| |
| --Q6 |
| select |
| sum(l_extendedprice * l_discount) as revenue |
| from |
| lineitem |
| where |
| l_shipdate >= date '1994-01-01' |
| and l_shipdate < date '1994-01-01' + interval '1' year |
| and l_discount between .06 - 0.01 and .06 + 0.01 |
| and l_quantity < 24; |
| |
| --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 ( |
| (n1.n_name = 'FRANCE' and n2.n_name = 'GERMANY') |
| or (n1.n_name = 'GERMANY' and n2.n_name = 'FRANCE') |
| ) |
| 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; |
| |
| --Q8 |
| |
| select |
| o_year, |
| sum(case |
| when nation = 'BRAZIL' 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 = 'AMERICA' |
| and s_nationkey = n2.n_nationkey |
| and o_orderdate between date '1995-01-01' and date '1996-12-31' |
| and p_type = 'ECONOMY ANODIZED STEEL' |
| ) as all_nations |
| group by |
| o_year |
| order by |
| o_year; |
| |
| --Q9 |
| 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 '%green%' |
| ) as profit |
| group by |
| nation, |
| o_year |
| order by |
| nation, |
| o_year desc; |
| |
| --Q10 |
| 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 '1993-10-01' |
| and o_orderdate < date '1993-10-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 |
| 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 = 'GERMANY' |
| group by |
| ps_partkey having |
| sum(ps_supplycost * ps_availqty) > ( |
| select |
| sum(ps_supplycost * ps_availqty) * 0.000002 |
| from |
| partsupp, |
| supplier, |
| nation |
| where |
| ps_suppkey = s_suppkey |
| and s_nationkey = n_nationkey |
| and n_name = 'GERMANY' |
| ) |
| order by |
| value desc; |
| |
| --Q12 |
| 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 ('MAIL', '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; |
| |
| --Q13 |
| select |
| c_count, |
| count(*) as custdist |
| from |
| ( |
| select |
| c_custkey, |
| count(o_orderkey) as c_count |
| from |
| customer left outer join orders on |
| c_custkey = o_custkey |
| and o_comment not like '%special%requests%' |
| group by |
| c_custkey |
| ) as c_orders |
| group by |
| c_count |
| order by |
| custdist desc, |
| c_count desc; |
| |
| --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 '1995-09-01' |
| and l_shipdate < date '1995-09-01' + interval '1' month; |
| |
| --Q15 |
| 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; |
| |
| --Q16 |
| 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#45' |
| and p_type not like 'MEDIUM POLISHED%' |
| and p_size in (49, 14, 23, 45, 19, 3, 36, 9) |
| 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; |
| |
| --Q17 |
| select |
| sum(l_extendedprice) / 7.0 as avg_yearly |
| from |
| lineitem, |
| part |
| where |
| p_partkey = l_partkey |
| and p_brand = 'Brand#23' |
| and p_container = 'MED BOX' |
| and l_quantity < ( |
| select |
| 0.2 * avg(l_quantity) |
| from |
| lineitem |
| where |
| l_partkey = p_partkey |
| ); |
| |
| --Q18 |
| 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) > 300 |
| ) |
| 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 |
| select |
| sum(l_extendedprice* (1 - l_discount)) as revenue |
| from |
| lineitem, |
| part |
| where |
| ( |
| p_partkey = l_partkey |
| and p_brand = 'Brand#12' |
| and p_container in ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG') |
| and l_quantity >= 1 and l_quantity <= 1 + 10 |
| and p_size between 1 and 5 |
| and l_shipmode in ('AIR', 'AIR REG') |
| and l_shipinstruct = 'DELIVER IN PERSON' |
| ) |
| or |
| ( |
| p_partkey = l_partkey |
| and p_brand = 'Brand#23' |
| and p_container in ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK') |
| and l_quantity >= 10 and l_quantity <= 10 + 10 |
| and p_size between 1 and 10 |
| and l_shipmode in ('AIR', 'AIR REG') |
| and l_shipinstruct = 'DELIVER IN PERSON' |
| ) |
| or |
| ( |
| p_partkey = l_partkey |
| and p_brand = 'Brand#34' |
| and p_container in ('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG') |
| and l_quantity >= 20 and l_quantity <= 20 + 10 |
| and p_size between 1 and 15 |
| and l_shipmode in ('AIR', 'AIR REG') |
| and l_shipinstruct = 'DELIVER IN PERSON' |
| ); |
| |
| --Q20 |
| select |
| s_name, |
| s_address |
| from |
| supplier, |
| nation |
| where |
| s_suppkey in ( |
| select |
| ps_suppkey |
| from |
| partsupp |
| where |
| ps_partkey in ( |
| select |
| p_partkey |
| from |
| part |
| where |
| p_name like 'forest%' |
| ) |
| and ps_availqty > ( |
| select |
| 0.5 * sum(l_quantity) |
| from |
| lineitem |
| where |
| l_partkey = ps_partkey |
| and l_suppkey = ps_suppkey |
| and l_shipdate >= date '1994-01-01' |
| and l_shipdate < date '1994-01-01' + interval '1' year |
| ) |
| ) |
| and s_nationkey = n_nationkey |
| and n_name = 'CANADA' |
| order by |
| s_name; |
| |
| --Q21 |
| select |
| s_name, |
| count(*) as numwait |
| from |
| supplier, |
| lineitem l1, |
| orders, |
| nation |
| where |
| s_suppkey = l1.l_suppkey |
| and o_orderkey = l1.l_orderkey |
| and o_orderstatus = 'F' |
| and l1.l_receiptdate > l1.l_commitdate |
| and exists ( |
| select |
| * |
| from |
| lineitem l2 |
| where |
| l2.l_orderkey = l1.l_orderkey |
| and l2.l_suppkey <> l1.l_suppkey |
| ) |
| and not exists ( |
| select |
| * |
| from |
| lineitem l3 |
| where |
| l3.l_orderkey = l1.l_orderkey |
| and l3.l_suppkey <> l1.l_suppkey |
| and l3.l_receiptdate > l3.l_commitdate |
| ) |
| and s_nationkey = n_nationkey |
| and n_name = 'SAUDI ARABIA' |
| group by |
| s_name |
| order by |
| numwait desc, |
| s_name |
| limit 100; |
| |
| --Q22 |
| select |
| cntrycode, |
| count(*) as numcust, |
| sum(c_acctbal) as totacctbal |
| from |
| ( |
| select |
| substring(c_phone, 1, 2) as cntrycode, |
| c_acctbal |
| from |
| customer |
| where |
| substring(c_phone, 1, 2) in |
| ('13', '31', '23', '29', '30', '18', '17') |
| and c_acctbal > ( |
| select |
| avg(c_acctbal) |
| from |
| customer |
| where |
| c_acctbal > 0.00 |
| and substring(c_phone, 1, 2) in |
| ('13', '31', '23', '29', '30', '18', '17') |
| ) |
| and not exists ( |
| select |
| * |
| from |
| orders |
| where |
| o_custkey = c_custkey |
| ) |
| ) as custsale |
| group by |
| cntrycode |
| order by |
| cntrycode; |
| |
| ``` |
| |