并行查询测试方法

本文将基于TPC-H基准测试,对PolarDB MySQL 8.0集群版进行OLAP负载性能测试。您可以按照本文所述的方法自行进行测试对比,从而快速了解该集群的性能。

测试环境

  • ECS实例和PolarDB MySQL集群位于同一地域,同一专有网络VPC内。

  • PolarDB MySQL集群配置如下:

    • 集群个数:1

    • 数据库引擎MySQL 8.0.1MySQL 8.0.2

    • 产品版本企业版

    • 系列集群版

    • 子系列独享规格

    • 节点规格:polar.mysql.x8.4xlarge(32256 GB)

    • 节点数量:2个(1个读写节点、1个只读节点)

    说明

    并行测试使用的连接地址为主地址。如何查看PolarDB MySQL集群的主地址,请参见管理连接地址

  • ECS实例配置如下:

    • 实例个数:1

    • 实例规格:ecs.c5.4xlarge(16 vCPU 32 GiB)

    • 镜像:CentOS 7.0 64

    • 系统盘:ESSD云盘1000 GB

测试工具

TPC-H是业界常用的一套基准,由TPC委员会制定发布,用于评测数据库的分析型查询能力。TPC-H查询包含8张数据表、22条复杂的SQL查询,大多数查询包含若干表Join、子查询和Group By聚合等。

说明

本文的TPC-H的实现基于TPC-H的基准测试,并不能与已发布的TPC-H基准测试结果相比较,本文中的测试并不符合TPC-H基准测试的所有要求。

安装TPC-H

重要
  • 请使用root用户登录ECS实例并执行以下命令。

  • 此处使用的TPC-H版本为TPC-H_Tools_v2.18.0,您需要先进行注册,注册完成后才能下载。

ECS实例上安装TPC-H的操作步骤如下:

  1. 注册并下载TPC-H,并将下载的TPC-H压缩包上传至ECS实例。上传操作步骤,请参见上传文件

  2. 解压缩上传的TPC-H压缩包。此处以TPC-H-Tool.zip为例,执行命令时,请根据实际情况修改压缩包名称。

    unzip TPC-H-Tool.zip
  3. 解压完成后,请进入文件夹并找到dbgen文件夹,随后进入该dbgen文件夹。此处以TPC-H-Tool/dbgen为例,执行命令时,请根据实际情况修改目录。

    cd TPC-H-Tool/dbgen
  4. 复制makefile文件。

    cp makefile.suite makefile
  5. 安装GCC。

    sudo yum install gcc
    说明

    此处以CentOS系统为例。如果您安装的是其他操作系统,请根据实际情况调整相应的安装命令。例如,在Ubuntu系统中,安装命令为sudo apt install gcc

  6. 修改makefile文件中的CCDATABASEMACHINEWORKLOAD参数的值。

    1. 打开makefile文件。

      vim makefile
    2. i键,修改参数值。

      ################
      ## CHANGE NAME OF ANSI COMPILER HERE
      ################
      CC      = gcc
      # Current values for DATABASE are: INFORMIX, DB2, TDAT (Teradata)
      #                                  SQLSERVER, SYBASE, ORACLE, VECTORWISE
      # Current values for MACHINE are:  ATT, DOS, HP, IBM, ICL, MVS, 
      #                                  SGI, SUN, U2200, VMS, LINUX, WIN32 
      # Current values for WORKLOAD are:  TPCH
      DATABASE= MYSQL
      MACHINE = LINUX
      WORKLOAD = TPCH
    3. Esc键,输入:wq保存并退出。

  7. 修改tpcd.h文件,并添加新的宏定义。

    1. 打开tpcd.h文件。

      vim tpcd.h
    2. i键,在database portability defines下添加如下宏定义。

      #ifdef MYSQL
      #define GEN_QUERY_PLAN "EXPLAIN PLAN"
      #define START_TRAN "START TRANSACTION"
      #define END_TRAN "COMMIT"
      #define SET_OUTPUT ""
      #define SET_ROWCOUNT "limit %d;\n"
      #define SET_DBASE "use %s;\n"
      #endif
    3. Esc键,然后输入:wq保存并退出。

  8. 对文件进行编译。

    make

    编译完成后该目录下会生成两个可执行文件:

    • dbgen:数据生成工具。在使用InfiniDB官方测试脚本进行测试时,需要用该工具生成TPC-H相关表数据。

    • qgen:SQL生成工具。生成初始化测试查询,由于不同的seed生成的查询不同,为了结果的可重复性,请使用附件提供的22个查询语句。

  9. 使用TPC-H生成测试数据。

    ./dbgen -s 100
    说明

    -s 参数用于指定生成数据的比例因子(Scale Factor),表示基准测试数据集的大小。-s 100 表示生成一个约100 GB的测试数据集(具体大小可能因表结构和数据分布略有差异)。

  10. (可选)使用TPC-H生成查询。

    说明

    为了测试结果可重复,您可以忽略下面生成查询的步骤,使用附件22个查询进行测试。

    1. qgendists.dss复制到queries目录下。

      cp qgen queries
      cp dists.dss queries
    2. 生成查询。

      1. 创建generate_queries.sh脚本。

        vim generate_queries.sh
      2. i键,添加如下脚本内容。

        #!/usr/bin/bash
        
        # 进入查询目录
        cd queries
        
        # 生成 22 条查询
        for i in {1..22}
        do
          ./qgen -d $i -s 100 > db"$i".sql
        done
      3. Esc键,然后输入:wq保存并退出。

      4. 设置脚本执行权限。

        chmod +x generate_queries.sh
      5. 执行generate_queries.sh脚本。

        ./generate_queries.sh

测试步骤

ECS实例上连接PolarDB MySQL集群,进行初始化数据及测试,操作步骤如下:

  1. 创建加载数据的执行脚本。

    1. TPC-Hdbgen目录下,创建load.ddl文件。

      vim load.ddl
    2. i键,添加如下脚本内容。

      load data local INFILE 'customer.tbl' INTO TABLE customer FIELDS TERMINATED BY '|';
      load data local INFILE 'region.tbl' INTO TABLE region FIELDS TERMINATED BY '|';
      load data local INFILE 'nation.tbl' INTO TABLE nation FIELDS TERMINATED BY '|';
      load data local INFILE 'supplier.tbl' INTO TABLE supplier FIELDS TERMINATED BY '|';
      load data local INFILE 'part.tbl' INTO TABLE part FIELDS TERMINATED BY '|';
      load data local INFILE 'partsupp.tbl' INTO TABLE partsupp FIELDS TERMINATED BY '|';
      load data local INFILE 'orders.tbl' INTO TABLE orders FIELDS TERMINATED BY '|';
      load data local INFILE 'lineitem.tbl' INTO TABLE lineitem FIELDS TERMINATED BY '|';
    3. Esc键,然后输入:wq保存并退出。

  2. 修改dss.ri文件,用于后续创建表的主外键。

    1. 复制dss.ri文件,并清空dss.ri文件。

      cp dss.ri dss_bk.ri
      > dss.ri
    2. 打开dss.ri文件。

      vim dss.ri
    3. i键,在文件中添加如下内容。

      use tpch100g;
      -- ALTER TABLE REGION DROP PRIMARY KEY;
      -- ALTER TABLE NATION DROP PRIMARY KEY;
      -- ALTER TABLE PART DROP PRIMARY KEY;
      -- ALTER TABLE SUPPLIER DROP PRIMARY KEY;
      -- ALTER TABLE PARTSUPP DROP PRIMARY KEY;
      -- ALTER TABLE ORDERS DROP PRIMARY KEY;
      -- ALTER TABLE LINEITEM DROP PRIMARY KEY;
      -- ALTER TABLE CUSTOMER DROP PRIMARY KEY;
      -- For table REGION
      ALTER TABLE REGION
      ADD PRIMARY KEY (R_REGIONKEY);
      -- For table NATION
      ALTER TABLE NATION
      ADD PRIMARY KEY (N_NATIONKEY);
      ALTER TABLE NATION
      ADD FOREIGN KEY NATION_FK1 (N_REGIONKEY) references REGION(R_REGIONKEY);
      COMMIT WORK;
      -- For table PART
      ALTER TABLE PART
      ADD PRIMARY KEY (P_PARTKEY);
      COMMIT WORK;
      -- For table SUPPLIER
      ALTER TABLE SUPPLIER
      ADD PRIMARY KEY (S_SUPPKEY);
      ALTER TABLE SUPPLIER
      ADD FOREIGN KEY SUPPLIER_FK1 (S_NATIONKEY) references NATION(N_NATIONKEY);
      COMMIT WORK;
      -- For table PARTSUPP
      ALTER TABLE PARTSUPP
      ADD PRIMARY KEY (PS_PARTKEY,PS_SUPPKEY);
      COMMIT WORK;
      -- For table CUSTOMER
      ALTER TABLE CUSTOMER
      ADD PRIMARY KEY (C_CUSTKEY);
      ALTER TABLE CUSTOMER
      ADD FOREIGN KEY CUSTOMER_FK1 (C_NATIONKEY) references NATION(N_NATIONKEY);
      COMMIT WORK;
      -- For table LINEITEM
      ALTER TABLE LINEITEM
      ADD PRIMARY KEY (L_ORDERKEY,L_LINENUMBER);
      COMMIT WORK;
      -- For table ORDERS
      ALTER TABLE ORDERS
      ADD PRIMARY KEY (O_ORDERKEY);
      COMMIT WORK;
      -- For table PARTSUPP
      ALTER TABLE PARTSUPP
      ADD FOREIGN KEY PARTSUPP_FK1 (PS_SUPPKEY) references SUPPLIER(S_SUPPKEY);
      COMMIT WORK;
      ALTER TABLE PARTSUPP
      ADD FOREIGN KEY PARTSUPP_FK2 (PS_PARTKEY) references PART(P_PARTKEY);
      COMMIT WORK;
      -- For table ORDERS
      ALTER TABLE ORDERS
      ADD FOREIGN KEY ORDERS_FK1 (O_CUSTKEY) references CUSTOMER(C_CUSTKEY);
      COMMIT WORK;
      -- For table LINEITEM
      ALTER TABLE LINEITEM
      ADD FOREIGN KEY LINEITEM_FK1 (L_ORDERKEY)  references ORDERS(O_ORDERKEY);
      COMMIT WORK;
      ALTER TABLE LINEITEM
      ADD FOREIGN KEY LINEITEM_FK2 (L_PARTKEY,L_SUPPKEY) references 
              PARTSUPP(PS_PARTKEY,PS_SUPPKEY);
      COMMIT WORK;
    4. Esc键,然后输入:wq保存并退出。

  3. 安装MySQL客户端。

    sudo yum install mysql
    说明

    此处以CentOS系统为例。如果您安装的是其他操作系统,请根据实际情况调整相应的安装命令。

  4. 使用高权限账号及集群主地址连接PolarDB MySQL集群。更多信息,请参见创建高权限账号连接数据库

    mysql -h<PolarDB集群主地址> -P<端口> -u<数据库用户名> -p<数据库用户密码>
    说明

    如果出现类Access denied for user 'xxx'@'xxx' (using password: YES)的错误提示,说明数据库用户名或密码不正确,请检查您输入的信息是否正确。

  5. 创建tpch100g数据库,并切换至当前数据库。

    CREATE DATABASE tpch100g;
    
    use tpch100g;
  6. 创建表。

    source ./dss.ddl
    说明

    dss.ddl位于TPC-Hdbgen目录中。

  7. 加载数据。

    source ./load.ddl
    说明

    load.ddl位于TPC-Hdbgen目录中,并在第一步进行了创建。

  8. 创建主外键。

    source ./dss.ri
    说明

    dss.ri位于TPC-Hdbgen目录中,并在第二步进行了修改。

  9. (可选)创建索引。

    您需要先执行exit;命令退出MySQL客户端。随后在ECS实例中,创建脚本并执行。脚本内容如下:

    #!/usr/bin/bash
    host=$1
    port=$2
    user=$3
    password=$4
    db=$5
    sqls=("create index i_s_nationkey on supplier (s_nationkey);"
    "create index i_ps_partkey on partsupp (ps_partkey);"
    "create index i_ps_suppkey on partsupp (ps_suppkey);"
    "create index i_c_nationkey on customer (c_nationkey);"
    "create index i_o_custkey on orders (o_custkey);"
    "create index i_o_orderdate on orders (o_orderdate);"
    "create index i_l_orderkey on lineitem (l_orderkey);"
    "create index i_l_partkey on lineitem (l_partkey);"
    "create index i_l_suppkey on lineitem (l_suppkey);"
    "create index i_l_partkey_suppkey on lineitem (l_partkey, l_suppkey);"
    "create index i_l_shipdate on lineitem (l_shipdate);"
    "create index i_l_commitdate on lineitem (l_commitdate);"
    "create index i_l_receiptdate on lineitem (l_receiptdate);"
    "create index i_n_regionkey on nation (n_regionkey);"
    "analyze table supplier"
    "analyze table part"
    "analyze table partsupp"
    "analyze table customer"
    "analyze table orders"
    "analyze table lineitem"
    "analyze table nation"
    "analyze table region")
    for sql in "${sqls[@]}"
    do
        mysql -h$host -P$port -u$user -p$password -D$db  -e "$sql"
    done
    说明
    • 创建脚本时,请确保脚本具有可执行权限。此处以create_indexes.sh脚本为例,您可以使用命令chmod +x create_indexes.sh来添加脚本的可执行权限。

    • 执行脚本时,您需要传递相应的参数。此处以create_indexes.sh脚本为例,执行命令为./create_indexes.sh <host> <port> <user> <password> <database>。参数说明如下:

      • <host>:集群连接地址

      • <port>:集群端口

      • <user>:数据库用户名

      • <password>:数据库用户密码

      • <database>:数据库名称

    • 在执行脚本时,如果出现警告信息[Warning] Using a password on the command line interface can be insecure,是由于脚本内部使用了mysql -h<数据库连接地址> -P<数据库端口> -u<数据库账号> -p<数据库密码> -e<SQL>命令。因此,系统会提示在命令行输入密码可能会导致系统上的其他用户通过执行ps等命令查看到密码。这一警告不会影响您的操作,操作完成后,您可以前往PolarDB控制台修改数据库账号密码。

    • 为了更有效地衡量并行查询带来的性能提升,您可以通过如下脚本将使用到的索引数据预加载到内存池中。

      #!/bin/bash
      host=$1
      port=$2
      user=$3
      password=$4
      dbname=$5
      MYSQL="mysql -h$host -P$port -u$user -p$password -D$dbname"
      if [ -z ${dbname} ]; then
          echo "dbname not defined."
          exit 1
      fi
      table_indexes=(
              "supplier PRIMARY"
              "supplier i_s_nationkey"
              "part PRIMARY"
              "partsupp PRIMARY"
              "partsupp i_ps_partkey"
              "partsupp i_ps_suppkey"
              "customer PRIMARY"
              "customer i_c_nationkey"
              "orders PRIMARY"
              "orders i_o_custkey"
              "orders i_o_orderdate"
              "lineitem PRIMARY"
              "lineitem i_l_orderkey"
              "lineitem i_l_partkey"
              "lineitem i_l_suppkey"
              "lineitem i_l_partkey_suppkey"
              "lineitem i_l_shipdate"
              "lineitem i_l_commitdate"
              "lineitem i_l_receiptdate"
              "nation i_n_regionkey"
              "nation PRIMARY"
              "region PRIMARY"
      )
      for table_index in "${table_indexes[@]}"
      do
          ti=($table_index)
          table=${ti[0]}
          index=${ti[1]}
          SQL="select count(*) from ${table} force index(${index})"
          echo "$MYSQL -e '$SQL'"
          $MYSQL -e "$SQL"
      done
  10. 运行查询

    您需要先执行exit;命令退出MySQL客户端。随后在ECS实例中,创建脚本并执行。脚本内容如下:

    #!/usr/bin/env bash
    host=$1
    port=$2
    user=$3
    password=$4
    database=$5
    resfile=$6
    echo "start test run at"`date "+%Y-%m-%d %H:%M:%S"`|tee -a ${resfile}.out
    for (( i=1; i<=22;i=i+1 ))
    do
    queryfile="./queries/Q"${i}".sql"
    start_time=`date "+%s.%N"`
    echo "run query ${i}"|tee -a ${resfile}.out
    mysql -h ${host}  -P${port} -u${user} -p${password} $database -e" source $queryfile;" |tee -a ${resfile}.out
    end_time=`date "+%s.%N"`
    start_s=${start_time%.*}
    start_nanos=${start_time#*.}
    end_s=${end_time%.*}
    end_nanos=${end_time#*.}
    if [ "$end_nanos" -lt "$start_nanos" ];then
            end_s=$(( 10#$end_s -1 ))
            end_nanos=$(( 10#$end_nanos + 10 ** 9))
    fi
    time=$(( 10#$end_s - 10#$start_s )).`printf "%03d\n" $(( (10#$end_nanos - 10#$start_nanos)/10**6 ))`
    echo ${queryfile} "the "${j}" run cost "${time}" second start at"`date -d @$start_time "+%Y-%m-%d %H:%M:%S"`" stop at"`date -d @$end_time "+%Y-%m-%d %H:%M:%S"` >> ${resfile}.time
    done
    说明
    • 执行脚本前,确认事项如下:

      • 请确保脚本具有可执行权限。此处以run_queries.sh脚本为例,您可以使用命令chmod +x run_queries.sh来添加脚本的可执行权限。

      • 请确认您当前所在的目录,该脚本内容是以在TPC-Hdbgen目录下执行为例进行编写的。请根据实际情况对queryfile="./queries/Q"${i}".sql"的内容进行相应修改。否则,您将遇到如下错误提示:ERROR at line 1: Failed to open file 'QXX.sql'

      • 请确认您已将附件22个查询上传并解压至dbgen/queries目录下。若需使用其他查询语句,请根据实际情况对queryfile="./queries/Q"${i}".sql"的内容进行相应修改。否则,您将遇到如下错误提示:ERROR at line 1: Failed to open file 'QXX.sql'

    • 执行脚本时,您需要传递相应的参数。此处以run_queries.sh脚本为例,执行命令为./run_queries.sh <host> <port> <user> <password> <database> <resfile>。参数说明如下:

      • <host>:集群连接地址

      • <port>:集群端口

      • <user>:集群用户名

      • <password>:集群用户密码

      • <database>:数据库名称

      • <resfile>:执行结果输出文件名称

    • 在执行脚本时,如果出现警告信息[Warning] Using a password on the command line interface can be insecure,是由于脚本内部使用了mysql -h<数据库连接地址> -P<数据库端口> -u<数据库账号> -p<数据库密码> -e<SQL>命令。因此,系统会提示在命令行输入密码可能会导致系统上的其他用户通过执行ps等命令查看到密码。这一警告不会影响您的操作,操作完成后,您可以前往PolarDB控制台修改数据库账号密码。

测试结果

并行查询性能测试,请参见并行查询性能