Doris (1) - データ テーブルの導入、アーキテクチャ、コンパイル、インストール、および基本的な使用

目次

1.ドリスの紹介

Doris は Baidu Big Data によって開発された、超並列処理用の最新の MPP (超並列処理) 分析データベース製品です。クエリ結果はわずか 1 秒未満の応答時間で取得でき、リアルタイムのデータ分析を効果的にサポートします。
Apache Doris の分散アーキテクチャは非常にシンプルで、操作と保守が簡単で、10 PB を超える非常に大きなデータ セットをサポートできます。
Apache Doris は、固定された履歴レポート、リアルタイムのデータ分析、インタラクティブな
データ分析、探索的データ分析など、さまざまなデータ分析のニーズを満たすことができます。
ここに画像の説明を挿入

ここに画像の説明を挿入

2. ドリス URL

1.公式サイトアドレス
2.資料閲覧アドレス
3.ダウンロードアドレス
4.GitHubアドレス

3. ドリス建築

ここに画像の説明を挿入
Doris のアーキテクチャは非常にシンプルです. FE (フロントエンド) と BE (バックエンド) の 2 つの役割と 2 つのプロセスのみを持ち、外部コンポーネントに依存しないため、展開と運用と保守に便利です. FE と BE の両方を使用できます.直線的に拡大します。

  • フロントエンド (FE) は、クラスター メタデータを格納および維持します。クエリ リクエストの受信と解析、クエリ プランの計画、クエリ実行のスケジューリング、およびクエリ結果の返信を担当します。主な役割は 3 つあります。
    1) リーダーとフォロワー: 主にメタ​​データの高可用性を実現するために使用され、単一のノードがダウンしたときに、サービス全体に影響を与えることなくメタデータをリアルタイムでオンラインで復元できるようにします。
    2) オブザーバー: クエリ ノードを拡張するために使用され、メタデータ バックアップの役割も果たします。クラスターの負荷が非常に高く、クエリ全体の機能を拡張する必要がある場合は、オブザーバー ノードを追加できます。オブザーバーは書き込みには参加せず、読み取りのみに参加します。

  • バックエンド (BE) は、物理データの格納と計算を担当し、FE によって生成された物理計画に従って、クエリが分散方式で実行されます。
    データの信頼性は BE によって保証され、BE はデータ全体の複数のコピーまたは 3 つのコピーを保存します。必要に応じて、コピーの数を動的に調整できます。

  • MySQLClient: MySQL プロトコルの助けを借りて、Doris は任意の MySQL ODBC/JDBC および MySQL クライアントを使用して Doris に直接アクセスできます。

  • ブローカー: ブローカーは独立したステートレス プロセスです。ファイル システム インターフェイスをカプセル化し、HDFS、S3、BOS などのリモート ストレージ システム内のファイルを読み取る機能を Doris に提供します。

3. コンパイルとインストール

3.1. ソフトウェアおよびハードウェア要件

概要
オープン ソースの MPP アーキテクチャ OLAP データベースである Doris は、ほとんどの主流の商用サーバーで実行できます。MPP アーキテクチャの同時実行の利点と Doris の高可用性機能を最大限に活用するために、Doris の展開は次の要件に従うことをお勧めします。
Linux オペレーティング システムのバージョン要件

Linux システム バージョン
CentOS 7.1以上
Ubuntu 16.04 以降

ソフトウェア要件

ソフトウェア バージョン
ジャワ 1.8以上
GCC 4.8.2 以降

オペレーティング システムのインストール要件
システムで開いているファイル ハンドルの最大数を設定する

vi /etc/security/limits.conf 
* soft nofile 65536
* hard nofile 65536

時計の同期
Doris のメタデータは 5000 ミリ秒未満の時間精度を必要とするため、クラスター内のすべてのマシンは時計を同期して、時計の問題によるメタデータの不一致によって引き起こされるサービス例外を回避する必要があります。

スワップ パーティション (スワップ) をオフにする
Linux スワップ パーティションは Doris に重大なパフォーマンスの問題をもたらすため、インストールの前にスワップ パーティションを無効にする必要があります。

Liunx ファイル システム
ここでは ext4 ファイル システムを使用することをお勧めします.オペレーティング システムをインストールするときは、ext4 ファイル システムを選択してください.
開発およびテスト環境

モジュール CPU メモリー ディスク 通信網 インスタンス数
フロントエンド 8コア+ 8GB以上 SSD または SATA、10GB+* ギガビット イーサネット 1
バックエンド 8コア+ 16GB以上 SSD または SATA、50GB 以上 * ギガビット イーサネット 1-3 *

本番環境

モジュール CPU メモリー ディスク 通信網 インスタンス数 (最小要件)
フロントエンド 16コア以上 64GB以上 SSD または RAID カード、100GB 以上 * 10 ギガビット NIC 1-3 *
バックエンド 16コア以上 64GB以上 SSD または SATA、100G+* 10 ギガビット NIC 3 *

注 1:
1. FE のディスク領域は、主にログや画像などのメタデータを格納するために使用されます。通常、数百 MB から数 GB の範囲です。
2. BE のディスク領域は、主にユーザー データの格納に使用されます. 総ディスク領域は、ユーザー データの総量 * 3 (3 コピー) によって計算され、さらに、領域の 40% がバックグラウンドの圧縮および圧縮のために予約されます。いくつかの中間データの保存。
3. 1 台のマシンに複数の BE インスタンスを展開できますが、展開できる FE は 1 つだけです。データのコピーが 3 つ必要な場合は、BE インスタンスをデプロイするために少なくとも 3 台のマシンが必要です (1 台のマシンで 3 つの BE インスタンスをデプロイするのではなく)。複数の FE が配置されているサーバーのクロックが一致している必要があります (最大 5 秒のクロックのずれが許容されます)
4. テスト環境は、1 つの BE のみでテストすることもできます。実際の運用環境では、BE インスタンスの数が全体的なクエリのレイテンシを直接決定します。
5. すべての展開ノードが Swap を閉じます。
6. FE の役割は、フォロワーとオブザーバーに分けられます (リーダーは、フォロワー グループで選出された役割であり、以下、総称してフォロワーと呼びます)。
FE ノード データは少なくとも 1 つ (1 フォロワー) です。1 フォロワーと 1 オブザーバーをデプロイすると、読み取りの高可用性を実現できます。3 フォロワーをデプロイすると、読み取りと書き込みの高可用性 (HA) を実現できます。
7. フォロワーの数は奇数でなければならず、オブザーバーの数は任意です。
8. 過去の経験に基づいて、クラスターの可用性要件が高い場合 (オンライン サービスの提供など)、3 つのフォロワーと 1 ~ 3 つのオブザーバーをデプロイできます。オフライン業務の場合、フォロワー1名とオブザーバー1~3名の配置が推奨されます。
9. ブローカーは、外部データ ソース (HDFS など) にアクセスするために使用されるプロセスです。通常、各マシンに 1 つのブローカー インスタンスをデプロイするだけで十分です。

デフォルトのポート番号:

インスタンス名 ポート名 デフォルトポート 通信方向 例証する
なれ be_port 9060 FE --> BE FE からのリクエストを受信するために使用される、BE 上の Thrift サーバーのポート
なれ webserver_port 8040 BE <–> BE BE 上の http サーバーのポート
なれ heartbeat_service_port 9050 FE --> BE FE からハートビートを受信するために使用される、BE のハートビート サービス ポート (thrift)
なれ brpc_port 8060 FE <–> BE, BE <–> BE BE 間の通信に使用される BE の brpc ポート
FE http_port 8030 FE <–> FE、ユーザー <–> FE FE の http サーバー ポート
FE rpc_port 9020 BE --> FE, FE <–> FE FE のリサイクル サーバー ポート。各 FE の構成は一貫している必要があります。
FE クエリ_ポート 9030 ユーザー <–> FE FE 上の mysql サーバー ポート
FE edit_log_port 9010 FE <–> FE FE 上の bdbje 間の通信に使用されるポート
ブローカ ブローカー_ipc_ポート 8000 FE --> ブローカー、BE --> ブローカー ブローカーのリサイクル サーバーは、リクエストの受信に使用されます

複数の FE インスタンスをデプロイする場合は、FE の http_port 構成が同じであることを確認してください。
展開する前に、各ポートに適切な方向のアクセス権があることを確認してください。
IP バインディング
複数のネットワーク カードの存在、または docker およびその他の環境のインストールに起因する仮想ネットワーク カードの存在により、同じホストが複数の異なる IP を持つ場合があります。現在 Doris は利用可能な IP を自動的に識別することができません。したがって、デプロイメント・ホストに複数の IP がある場合、priority_networks 構成項目を使用して、正しい IP を強制的に指定する必要があります。

priority_networks は FE と BE の両方の設定であり、fe.conf と be.conf に設定項目を記述する必要があります。この構成項目は、FE または BE の開始時にどの IP をバインドする必要があるかをプロセスに通知するために使用されます。例は次のとおりです。

priority_networks=10.1.3.0/24

これは CIDR 表記です。FE または BE は、この構成項目に従って、独自の localIP として一致する IP を探します。

注: priority_networks を構成して FE または BE を開始した後は、FE または BE の IP が正しくバインドされていることのみが確認されます。ADD BACKEND または ADD FRONTEND ステートメントを使用する場合は、priority_networks 構成に一致する IP も指定する必要があります。そうしないと、クラスターを確立できません。例:

BE の構成は次のとおりです。priority_networks=10.1.3.0/24

ただし、ADD BACKEND を使用する場合: ALTER SYSTEM ADD BACKEND "192.168.0.1:9050";

そうすると、FE と BE が正常に通信できなくなります。

このとき、誤って追加した BE を DROP し、正しい IP で ADD BACKEND を再度実行する必要があります。

FEも同じ。

BROKER には現在、priority_networks オプションがなく、必要ありません。ブローカーのサービスは、デフォルトで 0.0.0.0 にバインドされています。BROKER を追加するときは、正しいアクセス可能な BROKER IP を実行するだけです。

テーブル名の大文字と小文字の区別設定
doris のデフォルトは、テーブル名の大文字と小文字の区別です. テーブル名の大文字と小文字を区別しないという要件がある場合は、クラスターの初期化中に設定する必要があります. クラスタの初期化が完了した後は、テーブル名の大文字と小文字の区別を変更できません。

詳細については、変数の lower_case_table_names 変数の紹介を参照してください。

3.2、コンパイル

Doris をインストールするには、まずソース コードからコンパイルする必要がありますが、主な方法としては、Docker を使用してイメージ コンパイルを開発する方法 (推奨) と、直接コンパイルする方法があります。直接コンパイルする方法については、公式 Web サイト ( https://doris.apache.org/zh-CN/installing/compilation.html ) を参照してください。

3.2.1. Docker 環境のインストール

1) Docker では、CentOS システムのカーネル バージョンが 3.10 以上である必要があります。まず、システムのカーネル バージョンが要件を満たしているかどうかを確認します。

uname -r

2) root 権限でシステムにログインして、yum パッケージが最新のものに更新されていることを確認します。

sudo yum update -y

3) 古いバージョンをインストールしている場合は、最初に古いバージョンをアンインストールします

sudo yum remove docker docker-common docker-selinux docker-engine

4) yum-util ツールキットと devicemapper ドライバーの依存関係をインストールします。

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

5) yum ソースの設定 (yum のダウンロード速度を高速化)

sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

接続がタイムアウトした場合は、alibaba のミラー ソースを使用できます。

sudo yum-config-manager --add-repo
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

6) すべての倉庫のすべての docker バージョンを表示し、インストールする特定のバージョンを選択します.通常、最新バージョンを直接インストールできます

yum リスト docker-ce --showduplicates | 並べ替え -r

7) Docker をインストールします
(1) 最新の安定版をインストールする方法:

sudo yum install docker-ce -y #安定したウェアハウスのみがリポジトリでデフォルトで有効になっているため、最新の安定したバージョンがインストールされます

(2) 指定バージョンのインストール方法:

sudo yum install -y
# 例:
sudoyum install docker-ce-20.10.11.ce -y

8) 起動してブートスタートに参加

sudo systemctl start docker #docker を起動し
ます sudo systemctl enable docker #boot self-start を追加します

9) バージョンを確認して、インストールが成功したかどうかを確認します。

ドッカーのバージョン

クライアントとサーバーの 2 つの部分があれば、インストールが成功したことを証明します。

3.2.2. Docker を使用してイメージコンパイルを開発する

1) ソース コードをダウンロードして解凍
する wget 経由でダウンロードします (または、ダウンロードした圧縮パッケージを手動でアップロードします)。

wget
https://dist.apache.org/repos/dist/dev/incubator/doris/0.15/0.15.0-rc04/apache-doris-0.15.0-incubating-src.tar.gz

/opt/software/ に解凍します。

tar -zxvf apache-doris-0.15.0-incubating-src.tar.gz -C /opt/software

2) Docker イメージをダウンロードする

docker pull apache/インキュベータ-doris:build-env-for-0.15.0

次のコマンドを使用して、イメージがダウンロードされたかどうかを確認できます。

ドッカー画像

3) ローカル ディレクトリをマウントしてイメージを実行する
ローカルの Doris ソース コード ディレクトリをマウントしてイメージを実行し、コンパイルされたバイナリ ファイルがホスト マシンに保存され
、イメージが終了しても消えないようにします。同時に、イメージ内の maven の .m2 ディレクトリをホスト コンピューターのディレクトリにマウントして、
イメージがコンパイルされるたびに maven の依存ライブラリが繰り返しダウンロードされるのを防ぎます。

docker run -it
-v /opt/software/.m2:/root/.m2
-v /opt/software/apache-doris-0.15.0-incubating-src/:/root/apachedoris-0.15.0-incubating- src/
\apache/incubator-doris:build-env-for-0.15.0

4) JDK 8 に切り替える

代替 --set java java-1.8.0-openjdk.x86_64
代替 --set javac java-1.8.0-openjdk.x86_64
export JAVA_HOME=/usr/lib/jvm/java-1.8.0

5) Maven の依存関係を準備する
コンパイル プロセスは多くの依存関係をダウンロードします. 準備された doris-repo.tar.gz を
Docker によってマウントされた対応するディレクトリに解凍して、依存関係をダウンロードするプロセスを回避し、コンパイルを高速化することができます.

tar -zxvf doris-repo.tar.gz -C /opt/software

また、Alibaba Cloud ミラー ウェアハウスを指定して、ダウンロードを高速化することもできます。

vim /opt/software/apache-doris-0.15.0-incubating-src/fe/pom.xml

<repositories>标签下添加:
<repository>
 <id>aliyun</id>
 <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
vim /opt/software/apache-doris-0.15.0-incubating-src/be/pom.xml
在<repositories>标签下添加:
<repository>
 <id>aliyun</id>
 <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>

6) ドリスをコンパイルする

sh build.sh

build-env-for-0.15.0 以降を初めて使用する場合は、最初のコンパイル時に次のコマンドを使用します。

sh build.sh --clean --be --fe --ui

build-env-for-0.15.0 バージョン イメージは thrift (0.9 -> 0.13) をアップグレードするため、–clean コマンドを使用して新しいバージョンの thrift を強制的に使用してコード ファイルを生成する必要があります。そうしないと、互換性のないコードが表示されます
。 .

3.3. クラスターのデプロイメント

ホスト 1 ホスト 2 ホスト 3
FE(リーダー) FE(フォロワー) FE(オブザーバー)
なれ なれ なれ
ブローカ ブローカ ブローカ

本番環境では、FE と BE を分離することをお勧めします。

3.3.1. ディレクトリを作成し、コンパイル済みファイルをコピーする

1) ディレクトリを作成し、コンパイルされたファイルをコピーします

mkdir /opt/module/apache-doris-0.15.0 cp -r
/opt/software/apache-doris-0.15.0-incubating-src/output
/opt/module/apache-doris-0.15.0

2) 開いているファイルの数を変更します (ノードあたり)

sudo vim /etc/security/limits.conf

  • ソフトノファイル 65535
  • ハードノファイル 65535
  • ソフト nproc 65535
  • ハード nproc 65535

再起動は永続的に有効になりますが、ulimit -n 65535 を使用して一時的に有効にすることもできます。

3.3.2. FE ノードのデプロイ

1) fe メタデータ ストレージ用のディレクトリを作成します。

mkdir /opt/module/apache-doris-0.15.0/doris-meta

2) feの設定ファイルを修正する

vim /opt/module/apache-doris-0.15.0/fe/conf/fe.conf
#構成ファイルでメタデータ パスを指定します: meta_dir = /opt/module/apache-doris-0.15.0/doris-meta
#バインド IP を変更します (各マシンを独自の IP に変更します) priority_networks = 192.168.8.101/24

注:
⚫ 本番環境では、Doris のインストール ディレクトリに配置しない別のディレクトリを指定することを強く推奨し、別のディスクを使用することをお勧めします (SSD があれば最適です)。
⚫ イントラネットとエクストラネット、仮想マシン docker など、マシンに複数の IP がある場合、それらを正しく識別するために IP バインディングが必要です

⚫ JAVA_OPTS デフォルトの Java 最大ヒープメモリは 4GB です。本番環境を 8G 以上に調整することをお勧めします。
3) hadoop1 の FE を起動する

/opt/module/apache-doris-0.15.0/fe/bin/start_fe.sh --daemon

3.3.3. BE ノードの設定

1) BE を配布する

scp -r /opt/module/apache-doris-0.15.0/be hadoop2:/opt/module scp -r
/opt/module/apache-doris-0.15.0/be hadoop3:/opt/module

2) BEデータ格納ディレクトリの作成(各ノード)

mkdir /opt/module/apache-doris-0.15.0/doris-storage1 mkdir
/opt/module/apache-doris-0.15.0/doris-storage2

3) BE(各ノード)の設定ファイルを修正する

vim /opt/module/apache-doris-0.15.0/be/conf/be.conf
#構成ファイルでデータ ストレージ パスを指定します: storage_root_path = /opt/module/apache-doris-0.15.0/dorisstorage1;/ opt/ module/apache-doris-0.15.0/doris-storage2
# バインディング IP を変更します (各マシンは独自の IP に変更されます) priority_networks = 192.168.8.101/24

注:
⚫ storage_root_path はデフォルトで be/storage の下にあるため、このディレクトリを手動で作成する必要があります。複数のパスを区切るには、英語のセミコロン ; を使用します
(最後のディレクトリの後に追加しないでください)。
⚫ 記憶媒体が HDD か SSD かをパスで区別することが可能です。次のように、各パスの末尾に容量制限をカンマで区切って追加できます

:
/home/disk1/doris.HDD,50、ストレージ制限が 50 GB、HDD であることを意味します;
/home/disk2/doris.SSD,10、ストレージ制限が 10 GB、SSD、
/home/disk2/doris、ストレージ制限ですはディスクの最大容量で、デフォルトは HDD です
⚫ イントラネットとエクストラネット、仮想マシン docker など、マシンに複数の IP がある場合、正しく識別するために IP バインディングが必要です。

3.3.4. FE にすべての BE ノードを追加する

BE ノードは、クラスタに参加する前に FE に追加する必要があります。mysql-client を使用して FE に接続できます。
1) MySQL クライアントのインストール
(1) ディレクトリの作成

mkdir /opt/software/mysql-client/

(2) 以下の 3 つの rpm パッケージを /opt/software/mysql-client/ にアップロードし
ます
。 el7.x86_64.rpm
➢ mysql-community-libs-5.7.28-1.el7.x86_64.rpm
(3) 現在のシステムに MySQL がインストールされているかどうかを確認します

sudo rpm -qa|grep mariadb
#存在する場合は、最初にアンインストールします
sudo rpm -e --nodeps mariadb mariadb-libs mariadb-server

(4) インストール

rpm -ivh /opt/software/mysql-client/*

2) MySQL クライアントを使用して FE に接続する

mysql -h hadoop1 -P 9030 -uroot

デフォルトでは、root にはパスワードがなく、root パスワードは次のコマンドで変更できます。

SET PASSWORD FOR 'root' = PASSWORD('000000');

3) BE を追加する

ALTER SYSTEM ADD BACKEND “hadoop1:9050”;
ALTER SYSTEM ADD BACKEND “hadoop2:9050”;
ALTER SYSTEM ADD BACKEND “hadoop3:9050”;

4) BE ステータスの表示

SHOW PROC '/バックエンド';

3.3.5. BE の起動

1) BE の起動 (ノードごと)

/opt/module/apache-doris-0.15.0/be/bin/start_be.sh --daemon

2) BE ステータスの表示

mysql -h hadoop1 -P 9030 -uroot -p
SHOW PROC '/バックエンド';

Alive が true の場合、BE ノードが稼働していることを意味します。

3.3.6. FS_Broker のデプロイ (オプション)

ブローカーは Doris とは別に、プラグインの形でデプロイされます。サードパーティのストレージ システムからデータをインポートする必要がある場合は、対応する Broker をデプロイする必要があります.デフォルトでは、HDFS、Baidu Cloud BOS、および Amazon S3 を読み取るための fs_broker が提供されています。fs_broker はステートレスです。FE および BE ノードごとに Broker をデプロイすることをお勧めします。
1) FS_BROKER をコンパイルし、ファイルをコピーします
(1) ソース コード ディレクトリの下の fs_brokers ディレクトリに入り、sh build.sh を使用してコンパイルし
ます (2) ソース コード fs_broker の出力ディレクトリの下にある対応する Broker ディレクトリを、必要なすべてのノードにコピーします。展開し、名前を apache_hdfs_broker に変更します。BE または FE ディレクトリと同じレベルを維持することをお勧めします。
方法は2.2と同じです。
2) ブローカーを起動

/opt/module/apache-doris-0.15.0/apache_hdfs_broker/bin/start_broker.sh
–デーモン

3) Broker を追加するには
、Doris の FE と BE に Broker が存在するノードを知らせ、sql コマンドを使用して Broker ノード リストを追加します

(1) mysql-client を使用して、起動した FE に接続し、次のコマンドを実行します。

mysql -h hadoop1 -P 9030 -uroot -p
ALTER SYSTEM ADD BROKER broker_name “hadoop1:8000”,“hadoop2:8000”,“hadoop3:8000”;

これらのうち、broker_host は Broker が配置されているノード IP であり、broker_ipc_port は Broker 構成ファイルの conf/apache_hdfs_broker.conf にあります

4) ブローカーのステータスを表示
する

SHOW PROC "/ブローカー";


注: 本番環境では、すべてのインスタンスをデーモン プロセスで開始して、Supervisor (opens new window) などの終了後にプロセスが自動的にプルアップされるようにする必要があります。バージョン 0.9.0 以前でデーモンを使用して開始する必要がある場合は、
各 start_xx.sh スクリプトを変更して、最後の & 記号を削除する必要があります。バージョン 0.10.0 から、
sh start_xx.sh を直接呼び出すだけで起動します。

3.4. 容量の拡大と縮小

Doris は、FE、BE、および Broker インスタンスを簡単に拡張および縮小できます。

3.4.1 FE の拡大と縮小

FE の高可用性は、FE の容量を 3 ノード以上に拡張することで実現できます。
1) MySQL を使用してクライアントにログインした後、sql コマンドを使用して FE のステータスを確認できます.現在、FE は 1 つだけです。

mysql -h hadoop1 -P 9030 -uroot -p

SHOW PROC '/フロントエンド';

また、ページ アクセス、アクセス 8030、アカウントが root で、デフォルトのパスワードが空であり、入力する必要がないことで監視することもできます。
2) FE ノードの追加
FE は、リーダー、フォロワー、オブザーバーの 3 つの役割に分けられます。デフォルトでは、クラスターは 1 つのリーダーのみを持つことができ、複数のフォロワーとオブザーバーを持つことができます。リーダーとフォロワーは Paxos 選択グループを形成します. リーダーがダウンした場合、残りのフォロワーは自動的に新しいリーダーを選択して、高い書き込み可用性を確保します. オブザーバーはリーダーのデータを同期しますが、選挙には参加しません。
FE が 1 つだけ展開されている場合、その FE がデフォルトでリーダーになります。これに基づいて、いくつかのフォロワーとオブザーバーを追加できます。

ALTER SYSTEM ADD FOLLOWER “hadoop2:9010”;

ALTER SYSTEM ADD OBSERVER “hadoop3:9010”;

3) Follower と Observer の設定と起動
初回起動時、起動コマンドでパラメータを追加する必要があります --helper leader host: edit_log_port:
(1) FE の配布と FE の設定変更 (2.4.2 と同じ)

scp -r /opt/module/apache-doris-0.15.0/fe hadoop2:/opt/module/
apache-doris-0.15.0

scp -r /opt/module/apache-doris-0.15.0/fe hadoop3:/opt/module/
apache-doris-0.15.0

(2) hadoop2でフォロワーを起動

/opt/module/apache-doris-0.15.0/fe/bin/start_fe.sh --helper
hadoop1:9010 --daemon

(3) hadoop3 で Observer を起動する

/opt/module/apache-doris-0.15.0/fe/bin/start_fe.sh --helper
hadoop1:9010 --daemon

4) 実行ステータスの確認
mysql-client を使用して、開始された任意の FE に接続します。

SHOW PROC '/フロントエンド';

5) FE ノード削除コマンド

ALTER SYSTEM DROP FOLLOWER[OBSERVER] “fe_host:edit_log_port”;

注: フォロワー FE を削除するときは、最後に残っているフォロワー (リーダーを含む) ノードが奇数であることを確認してください。

3.4.2 BE の拡張と削減

1) BE ノードの追加
MySQL クライアントで、ALTER SYSTEM ADD BACKEND コマンドを使用して BE ノードを追加します。
2) BE ノードを削除するための DROP (非推奨)

ALTER SYSTEM DROP BACKEND “be_host:be_heartbeat_service_port”;

注: DROP BACKEND は BE を直接削除し、BE 上のデータは回復できなくなります。! ! そのため、DROP BACKEND を使用して BE ノードを削除することは強くお勧めしません。このステートメントを使用すると、対応する誤用防止プロンプトが表示されます。
3) BE ノードを削除する DECOMMISSION 方法 (推奨)

ALTER SYSTEM DECOMMISSION BACKEND
“be_host:be_heartbeat_service_port”;

⚫ このコマンドは、BE ノードを安全に削除するために使用されます。コマンドが発行された後、Doris は BE 上のデータを他の BE ノードに移行しようとします。すべてのデータが移行されると、Doris はノードを自動的に削除します。
⚫ このコマンドは非同期操作です。実行後、SHOW PROC '/backends'; を使用して、BE ノードの isDecommission ステータスが true であることを確認できます。ノードがオフラインになることを示します。
⚫ コマンドが正常に実行されない場合があります。たとえば、残りの BE ストレージ スペースがオフライン BE 上のデータを収容するのに十分でない場合、または残りのマシンの数がコピーの最小数を満たしていない場合、コマンドは完了できず、BE は常にisDecommission の状態は
true です。
⚫ DECOMMISSION の進行状況は、SHOW PROC '/backends' の TabletNum で確認できます; 進行中の場合、TabletNum は減少し続けます。
⚫ この操作は、次のコマンドでキャンセルできます。

破棄バックエンドのキャンセル “be_host:be_heartbeat_service_port”;

キャンセル後、BE 上のデータは現在の残りのデータ量を維持します。後続のドリスが負荷を再調整します。

3.4.3 ブローカーの拡大と縮小

Broker インスタンスの数に厳密な要件はありません。通常、物理マシンごとに 1 つあれば十分です。ブローカーの追加と削除は、次のコマンドで実行できます。

ALTER SYSTEM ADD BROKER broker_name “broker_host:broker_ipc_port”;

ALTER SYSTEM DROP BROKER broker_name “broker_host:broker_ipc_port”;

ALTER SYSTEM DROP ALL BROKER ブローカー名;

Broker は、自由に開始および停止できるステートレス プロセスです。もちろん、停止すると、実行中のジョブは失敗します。再試行するだけです。

4. データテーブルの基本的な使い方

4.1. ユーザーとデータベースの作成

1) テスト ユーザーを作成する

mysql -h hadoop1 -P 9030 -uroot -p
'test' で識別されるユーザー 'test' を作成します。

2) データベースを作成する

データベース test_db を作成します。

3) ユーザー認証

test_db のすべてをテストに付与します。

4.2. Doris におけるデータテーブルの基本概念

Doris では、データはリレーショナル テーブル (Table) の形式で論理的に記述されます。

4.2.1、行と列

テーブルには、行 (Row) と列 (Column) が含まれます。行は、ユーザー データの行です。列は、データ行のさまざまなフィールドを説明するために使用されます。

  • 既定のデータ モデルでは、列は並べ替えられた列と並べ替えられていない列にのみ分割されます。ストレージ エンジンは、並べ替え列に従ってデータを並べ替えて格納し、並べ替えられたデータを高速に検索するための疎インデックスを構築します。
  • 集計モデルでは、列をキーと値の 2 つのカテゴリに分けることができます。ビジネスの観点からは、キーと値はそれぞれディメンション列とインジケーター列に対応できます。集約モデルの観点から、同じキー列を持つ行は 1 つの行に集約されます。Value列の集計方法は、テーブル作成時にユーザーが指定します。

4.2.2、パーティション&タブレット

Dorisストレージエンジンでは、まずユーザーデータをいくつかのパーティション(Partition)に分割し、分割ルールは通常、時間などユーザーが指定したパーティション列に従って範囲を分割します。各パーティションでは、データは
ハッシュ方式に従ってさらにバケットに分割されます. バケット化ルールは、バケット化する前に、ユーザーが指定したバケット列の値をハッシュ用に見つけることです. 各バケットはデータ シャード (タブレット) であり、データ分割の最小の論理単位でもあります。

  • タブレット間のデータには交差がなく、独立して保存されます。タブレットは、データの移動や複製などの操作を行うための最小の物理ストレージ ユニットでもあります。
  • パーティションは、最小の論理的な管理単位と見なすことができます。データのインポートと削除は、1 つのパーティションに対してのみ行うことも、1 つのパーティションに対してのみ行うこともできます。

4.3. テーブルの作成例

4.3.1、テーブル作成構文

CREATE TABLE コマンドを使用して、テーブル (テーブル) を作成します。より詳細なパラメーターを表示できます。

テーブルの作成を手伝ってください。

テーブルの作成構文:

CREATE [EXTERNAL] TABLE [存在しない場合] [データベース
COMMENT「テーブルコメント」]; [partition_desc] [distribution_desc] [rollup_index] [PROPERTIES (“key”=“value”, …)] [BROKER PROPERTIES (“key”=“value”, …)];








Doris テーブルの作成は同期コマンドです. コマンドが正常に返された場合, テーブルの作成が成功したことを意味します.
Doris は、単一パーティションと複合パーティションという 2 つのテーブル構築方法をサポートしています。
1) 複合パーティション: パーティションとバケットの両方があり、
最初のレベルはパーティション、つまりパーティションと呼ばれます。ユーザーは、ディメンション列をパーティション列として指定し (現在、整数型と時間型の列のみがサポートされています)、各パーティションの値の範囲を指定できます。
2 番目のレベルは、分散、つまりバケット化と呼ばれます。ユーザーは、1 つ以上のディメンション列とバケット数を指定して、データに対して HASH 分散を実行できます。
2) 単一パーティション: HASH 分散のみ、つまりバケットのみを行います。

4.3.2、フィールドタイプ

フィールド型名 タイプバイト単位 長さ
TINYINT 1バイト 範囲: -2^7 + 1 ~ 2^7 - 1
SMALLINT 2バイト 範囲: -2^15 + 1 ~ 2^15 - 1
INT 4バイト 範囲: -2^31 + 1 ~ 2^31 - 1
BIGINT 8バイト 範囲: -2^63 + 1 ~ 2^63 - 1
LARGEINT 16バイト 範囲: -2^127 + 1 ~ 2^127 - 1
浮く 4バイト 科学表記法をサポート
ダブル 12バイト 科学表記法をサポート
DECIMAL[(精度、位取り)] 16バイト 精度が保証された 10 進数型。デフォルトは DECIMAL(10, 0) です 精度: 1 ~ 27 スケール: 0 ~ 9 整数部分が 1 ~ 18 の場合、指数表記はサポートされていません
日にち 3バイト 範囲: 0000-01-01 ~ 9999-12-31
日付時刻 8バイト 範囲: 0000-01-01 00:00:00 ~ 9999-12-31 23:59:59
CHAR[(長さ)] 固定長文字列。長さの範囲: 1 ~ 255。デフォルトは 1 です
VARCHAR[(長さ)] 可変長文字列。長さの範囲: 1 ~ 65533
ブール値 TINYINT と同様に、0 は false を意味し、1 は true を意味します。
HLL 1~16385バイト hll 列类型,不需要指定长度和默认值、长度根据数据的聚合程度系统内控制,并且 HLL 列只能通过 配 套 的 hll_union_agg 、Hll_cardinality、hll_hash 进行查询或使用
BITMAP bitmap 列类型,不需要指定长度和默认值。表示整型的集合,元素最大支持到 2^64 - 1
STRING 变长字符串,0.15 版本支持,最大支持 2147483643 字节(2GB-4),长度还受 be 配置string_type_soft_limit, 实际能存储的最大长度取两者最小值。只能用在 value 列,不能用在 key 列和分区、分桶列

注意:聚合模型在定义字段类型后,可以指定字段的 agg_type 聚合类型,如果不指定,则该列为 key 列。否则,该列为value 列, 类型包括:SUM、MAX、MIN、REPLACE。

4.3.3、Doris建表示例

4.3.3.1、Range Partition

CREATE TABLE IF NOT EXISTS example_db.expamle_range_tbl
(
 `user_id` LARGEINT NOT NULL COMMENT "用户 id",
 `date` DATE NOT NULL COMMENT "数据灌入日期时间",
 `timestamp` DATETIME NOT NULL COMMENT "数据灌入的时间戳",
 `city` VARCHAR(20) COMMENT "用户所在城市",
 `age` SMALLINT COMMENT "用户年龄",
 `sex` TINYINT COMMENT "用户性别",
 `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 
00:00:00" COMMENT "用户最后一次访问时间",
 `cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费",
 `max_dwell_time` INT MAX DEFAULT "0" COMMENT "用户最大停留时间",
 `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用户最小停留时间"
)
ENGINE=OLAP
AGGREGATE KEY(`user_id`,`date`,`timestamp`,`city`,`age`,`sex`)
partition by range(`date`)
(
PARTITION `p201701` VALUES LESS THAN ("2017-02-01"),
 PARTITION `p201702` VALUES LESS THAN ("2017-03-01"),
 PARTITION `p201703` VALUES LESS THAN ("2017-04-01")
)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 16 
PROPERTIES
(
"replication_num" = "3",
 "storage_medium" = "SSD",
 "storage_cooldown_time" = "2018-01-01 12:00:00"
)

 

4.3.3.2、 List Partition

CREATE TABLE IF NOT EXISTS example_db.expamle_list_tbl
(
 `user_id` LARGEINT NOT NULL COMMENT "用户 id",
 `date` DATE NOT NULL COMMENT "数据灌入日期时间",
 `timestamp` DATETIME NOT NULL COMMENT "数据灌入的时间戳",
 `city` VARCHAR(20) COMMENT "用户所在城市",
 `age` SMALLINT COMMENT "用户年龄",
 `sex` TINYINT COMMENT "用户性别",
 `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 
00:00:00" COMMENT "用户最后一次访问时间",
 `cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费",
 `max_dwell_time` INT MAX DEFAULT "0" COMMENT "用户最大停留时间",
 `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用户最小停留时
间"
)
ENGINE=olap
AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`)
PARTITION BY LIST(`city`)
(
 PARTITION `p_cn` VALUES IN ("Beijing", "Shanghai", "Hong Kong"),
 PARTITION `p_usa` VALUES IN ("New York", "San Francisco"),
 PARTITION `p_jp` VALUES IN ("Tokyo")
)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 16
PROPERTIES
(
 "replication_num" = "3",
 "storage_medium" = "SSD",
 "storage_cooldown_time" = "2018-01-01 12:00:00"
);

4.3.4、数据划分

4.3.4.1、列定义

以 AGGREGATE KEY 数据模型为例进行说明。更多数据模型参阅 Doris 数据模型。
列的基本类型,可以通过在 mysql-client 中执行 HELP CREATE TABLE; 查看。
AGGREGATE KEY 数据模型中,所有没有指定聚合方式(SUM、REPLACE、MAX、
MIN)的列视为 Key 列。而其余则为 Value 列。
定义列时,可参照如下建议:
➢ Key 列必须在所有 Value 列之前。
➢ 尽量选择整型类型。因为整型类型的计算和查找比较效率远高于字符串。
➢ 对于不同长度的整型类型的选择原则,遵循够用即可。
➢ 对于 VARCHAR 和 STRING 类型的长度,遵循 够用即可。
➢ 所有列的总字节长度(包括 Key 和 Value)不能超过 100KB。

4.3.4.2、分区与分桶

Doris 支持两层的数据划分。第一层是 Partition,支持 Range 和 List 的划分方式。第二层是 Bucket(Tablet),仅支持 Hash 的划分方式。
也可以仅使用一层分区。使用一层分区时,只支持 Bucket 划分。

4.3.4.2.1、Partition

➢ Partition 列可以指定一列或多列。分区类必须为 KEY 列。多列分区的使用方式在后面介绍。
➢ 不论分区列是什么类型,在写分区值时,都需要加双引号。
➢ 分区数量理论上没有上限。
➢ 当不使用 Partition 建表时,系统会自动生成一个和表名同名的,全值范围的
Partition。该 Partition 对用户不可见,并且不可删改。
1) Range 分区
分区列通常为时间列,以方便的管理新旧数据。不可添加范围重叠的分区。
Partition 指定范围的方式
⚫ VALUES LESS THAN (…) 仅指定上界,系统会将前一个分区的上界作为该分区的下界,生成一个左闭右开的区间。分区的删除不会改变已存在分区的范围。删除分区可能出现空洞。
⚫ VALUES […) 指定同时指定上下界,生成一个左闭右开的区间。
通过 VALUES […) 同时指定上下界比较容易理解。这里举例说明,当使用 VALUES
LESS THAN (…) 语句进行分区的增删操作时,分区范围的变化情况:
(1)如上 expamle_range_tbl 示例,当建表完成后,会自动生成如下 3 个分区:

p201701: [MIN_VALUE, 2017-02-01)
p201702: [2017-02-01, 2017-03-01)
p201703: [2017-03-01, 2017-04-01)

(2)增加一个分区 p201705 VALUES LESS THAN (“2017-06-01”),分区结果如下:

p201701: [MIN_VALUE, 2017-02-01)
p201702: [2017-02-01, 2017-03-01)
p201703: [2017-03-01, 2017-04-01)
p201705: [2017-04-01, 2017-06-01)

(3)此时删除分区 p201703,则分区结果如下:

p201701: [MIN_VALUE, 2017-02-01)
p201702: [2017-02-01, 2017-03-01)
p201705: [2017-04-01, 2017-06-01)

注意到 p201702 和 p201705 的分区范围并没有发生变化,而这两个分区之间,出现了一个空洞:[2017-03-01, 2017-04-01)。即如果导入的数据范围在这个空洞范围内,是无法导入的。
(4)继续删除分区 p201702,分区结果如下:

p201701: [MIN_VALUE, 2017-02-01)
p201705: [2017-04-01, 2017-06-01)

空洞范围变为:[2017-02-01, 2017-04-01)
(5)现在增加一个分区 p201702new VALUES LESS THAN (“2017-03-01”),分区结果如下:

p201701: [MIN_VALUE, 2017-02-01)
p201702new: [2017-02-01, 2017-03-01)
p201705: [2017-04-01, 2017-06-01)

可以看到空洞范围缩小为:[2017-03-01, 2017-04-01)
(6)现在删除分区 p201701,并添加分区 p201612 VALUES LESS THAN (“2017-01-01”),
分区结果如下:

p201612: [MIN_VALUE, 2017-01-01)
p201702new: [2017-02-01, 2017-03-01)
p201705: [2017-04-01, 2017-06-01)

即出现了一个新的空洞:[2017-01-01, 2017-02-01)
2)List 分区
分 区 列支 持 BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, DATE,
DATETIME, CHAR, VARCHAR 数据类型,分区值为枚举值。只有当数据为目标分区枚举值其中之一时,才可以命中分区。不可添加范围重叠的分区。
Partition 支持通过 VALUES IN (…) 来指定每个分区包含的枚举值。下面通过示例说明,
进行分区的增删操作时,分区的变化。
(1)如上 example_list_tbl 示例,当建表完成后,会自动生成如下 3 个分区:

p_cn: (“Beijing”, “Shanghai”, “Hong Kong”)
p_usa: (“New York”, “San
Francisco”) p_jp: (“Tokyo”)

(2)增加一个分区 p_uk VALUES IN (“London”),分区结果如下:

p_cn: (“Beijing”, “Shanghai”, “Hong Kong”)
p_usa: (“New York”, “San
Francisco”) p_jp: (“Tokyo”)
p_uk: (“London”)

(3)删除分区 p_jp,分区结果如下:

p_cn: (“Beijing”, “Shanghai”, “Hong Kong”)
p_usa: (“New York”, “San
Francisco”) p_uk: (“London”)

4.3.4.2.2、Bucket

(1)如果使用了 Partition,则 DISTRIBUTED … 语句描述的是数据在各个分区内的划分规则。如果不使用 Partition,则描述的是对整个表的数据的划分规则。
(2)分桶列可以是多列,但必须为 Key 列。分桶列可以和 Partition 列相同或不同。
(3)分桶列的选择,是在 查询吞吐 和 查询并发 之间的一种权衡:
① 如果选择多个分桶列,则数据分布更均匀。
如果一个查询条件不包含所有分桶列的等值条件,那么该查询会触发所有分桶同时扫描,这样查询的吞吐会增加,单个查询的延迟随之降低。这个方式适合大吞吐低并发的查询场景。
② 如果仅选择一个或少数分桶列,则对应的点查询可以仅触发一个分桶扫描。
此时,当多个点查询并发时,这些查询有较大的概率分别触发不同的分桶扫描,各个查询之间的 IO 影响较小(尤其当不同桶分布在不同磁盘上时),所以这种方式适合高并发的点查询场景。
(4)分桶的数量理论上没有上限。

4.3.4.2.3、使用复合分区的场景

以下场景推荐使用复合分区
(1)有时间维度或类似带有有序值的维度,可以以这类维度列作为分区列。分区粒度可以根据导入频次、分区数据量等进行评估。
(2)历史数据删除需求:如有删除历史数据的需求(比如仅保留最近 N 天的数据)。
使用复合分区,可以通过删除历史分区来达到目的。也可以通过在指定分区内发送 DELETE 语句进行数据删除。
(3)解决数据倾斜问题:每个分区可以单独指定分桶数量。如按天分区,当每天的数据量差异很大时,可以通过指定分区的分桶数,合理划分不同分区的数据,分桶列建议选择区分度大的列。

4.3.4.2.4、多列分区

4.3.4.3、PROPERTIES

在建表语句的最后 PROPERTIES 中,可以指定以下两个参数:

4.3.4.3.1 replication_num

每个 Tablet 的副本数量。默认为 3,建议保持默认即可。在建表语句中,所有 Partition 中的 Tablet 副本数量统一指定。而在增加新分区时,可以单独指定新分区中 Tablet 的副本数量。
副本数量可以在运行时修改。强烈建议保持奇数。
最大副本数量取决于集群中独立 IP 的数量(注意不是 BE 数量)。Doris 中副本分布的原则是,不允许同一个 Tablet 的副本分布在同一台物理机上,而识别物理机即通过 IP。所以,即使在同一台物理机上部署了 3 个或更多 BE 实例,如果这些 BE 的 IP 相同,则依然只能设置副本数为 1。
对于一些小,并且更新不频繁的维度表,可以考虑设置更多的副本数。这样在 Join 查询时,可以有更大的概率进行本地数据 Join。

4.3.4.3.2、storage_medium & storage_cooldown_time

BE 的数据存储目录可以显式的指定为 SSD 或者 HDD(通过 .SSD 或者 .HDD 后缀区分)。建表时,可以统一指定所有 Partition 初始存储的介质。注意,后缀作用是显式指定磁盘介质,而不会检查是否与实际介质类型相符。
默认初始存储介质可通过 fe 的配置文件 fe.conf 中指定 default_storage_medium=xxx,如果没有指定,则默认为 HDD。如果指定为 SSD,则数据初始存放在 SSD 上。
如果没有指定 storage_cooldown_time,则默认 30 天后,数据会从 SSD 自动迁移到 HDD 上。如果指定了 storage_cooldown_time,则在到达storage_cooldown_time 时间后,数据才会迁移。

注意,当指定 storage_medium 时,如果 FE 参数enable_strict_storage_medium_check 为False 该参数只是一个“尽力而为”的设置。即使集群内没有设置 SSD 存储介质,也不会报错,而是自动存储在可用的数据目录中。 同样,如果 SSD 介质不可访问、空间不足,都可能导致数据初始直接存储在其他可用介质上。而数据到期迁移到 HDD 时,如果 HDD 介质不 可 访 问 、 空 间 不 足 , 也 可 能 迁 移 失 败 ( 但 是 会 不 断 尝 试 ) 。 如 果 FE 参 数enable_strict_storage_medium_check 为 True 则当集群内没有设置 SSD 存储介质时,会报错Failed to find enough host in all backends with storage medium is SSD。

4.3.4.4、ENGINE

本示例中,ENGINE 的类型是 olap,即默认的 ENGINE 类型。在 Doris 中,只有这个ENGINE 类型是由 Doris 负责数据管理和存储的。其他 ENGINE 类型,如 mysql、broker、es 等等,本质上只是对外部其他数据库或系统中的表的映射,以保证 Doris 可以读取这些数据。而 Doris 本身并不创建、管理和存储任何非 olap ENGINE 类型的表和数据。

4.3.5 数据模型

Doris 的数据模型主要分为 3 类:Aggregate、Uniq、Duplicate

4.3.5.1 Aggregate 模型

表中的列按照是否设置了 AggregationType,分为 Key(维度列)和 Value(指标列)。没有设置 AggregationType 的称为 Key,设置了 AggregationType 的称为 Value。
当我们导入数据时,对于 Key 列相同的行会聚合成一行,而 Value 列会按照设置的AggregationType 进行聚合。AggregationType 目前有以下四种聚合方式:
➢ SUM:求和,多行的 Value 进行累加。
➢ REPLACE:替代,下一批数据中的 Value 会替换之前导入过的行中的 Value。
REPLACE_IF_NOT_NULL :当遇到 null 值则不更新。
➢ MAX:保留最大值。
➢ MIN:保留最小值。
数据的聚合,在 Doris 中有如下三个阶段发生:
(1)每一批次数据导入的 ETL 阶段。该阶段会在每一批次导入的数据内部进行聚合。
(2)底层 BE 进行数据 Compaction 的阶段。该阶段,BE 会对已导入的不同批次的数据进行进一步的聚合。
(3)数据查询阶段。在数据查询时,对于查询涉及到的数据,会进行对应的聚合。数据在不同时间,可能聚合的程度不一致。比如一批数据刚导入时,可能还未与之前已存在的数据进行聚合。但是对于用户而言,用户只能查询到聚合后的数据。即不同的聚合程度对于用户查询而言是透明的。用户需始终认为数据以最终的完成的聚合程度存在,而不应假设某些聚合还未发生。(可参阅聚合模型的局限性一节获得更多详情。)
3.5.1.1 示例一:导入数据聚合
1)建表

CREATE TABLE IF NOT EXISTS test_db.example_site_visit
(
 `user_id` LARGEINT NOT NULL COMMENT "用户 id",
 `date` DATE NOT NULL COMMENT "数据灌入日期时间",
 `city` VARCHAR(20) COMMENT "用户所在城市",
 `age` SMALLINT COMMENT "用户年龄",
 `sex` TINYINT COMMENT "用户性别",
`last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 
00:00:00" COMMENT "用户最后一次访问时间",
 `last_visit_date_not_null` DATETIME REPLACE_IF_NOT_NULL DEFAULT 
"1970-01-01 00:00:00" COMMENT "用户最后一次访问时间",
 `cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费",
 `max_dwell_time` INT MAX DEFAULT "0" COMMENT "用户最大停留时间",
 `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用户最小停留时
间"
)
AGGREGATE KEY(`user_id`, `date`, `city`, `age`, `sex`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 10;

2)插入数据

insert into test_db.example_site_visit values\
(10000,'2017-10-01','北京',20,0,'2017-10-01 06:00:00','2017-10-01 
06:00:00',20,10,10),\
(10000,'2017-10-01','北京',20,0,'2017-10-01 07:00:00','2017-10-01 
07:00:00',15,2,2),\
(10001,'2017-10-01','北京',30,1,'2017-10-01 17:05:45','2017-10-01 
07:00:00',2,22,22),\
(10002,'2017-10-02',' 上 海 ',20,1,'2017-10-02 
12:59:12',null,200,5,5),\
(10003,'2017-10-02','广州',32,0,'2017-10-02 11:20:00','2017-10-02 
11:20:00',30,11,11),\
(10004,'2017-10-01','深圳',35,0,'2017-10-01 10:00:15','2017-10-01 
10:00:15',100,3,3),\
(10004,'2017-10-03','深圳',35,0,'2017-10-03 10:20:22','2017-10-0310:20:22',11,6,6);


注意:Insert into 单条数据这种操作在 Doris 里只能演示不能在生产使用,会引发写阻塞.
3)查看表

select * from test_db.example_site_visit;

可以看到,用户 10000 只剩下了一行聚合后的数据。而其余用户的数据和原始数据保持一致。经过聚合,Doris 中最终只会存储聚合后的数据。换句话说,即明细数据会丢失,用户不能够再查询到聚合前的明细数据了。

4.3.5.1.2 示例二:保留明细数据

1)建表

CREATE TABLE IF NOT EXISTS test_db.example_site_visit2
(
 `user_id` LARGEINT NOT NULL COMMENT "用户 id",
 `date` DATE NOT NULL COMMENT "数据灌入日期时间",
 `timestamp` DATETIME COMMENT "数据灌入时间,精确到秒",
 `city` VARCHAR(20) COMMENT "用户所在城市",
 `age` SMALLINT COMMENT "用户年龄",
 `sex` TINYINT COMMENT "用户性别",
 `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 
00:00:00" COMMENT "用户最后一次访问时间",
 `cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费",
 `max_dwell_time` INT MAX DEFAULT "0" COMMENT "用户最大停留时间",
 `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用户最小停留时
间"
)
AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 10;

2)插入数据

insert into test_db.example_site_visit2 values(10000,'2017-10-
01','2017-10-01 08:00:05',' 北 京 ',20,0,'2017-10-01 
06:00:00',20,10,10),\
(10000,'2017-10-01','2017-10-01 09:00:05','北京',20,0,'2017-10-01 
07:00:00',15,2,2),\
(10001,'2017-10-01','2017-10-01 18:12:10','北京',30,1,'2017-10-01 
17:05:45',2,22,22),\
(10002,'2017-10-02','2017-10-02 13:10:00','上海',20,1,'2017-10-02 
12:59:12',200,5,5),\
(10003,'2017-10-02','2017-10-02 13:15:00','广州',32,0,'2017-10-02 
11:20:00',30,11,11),\
(10004,'2017-10-01','2017-10-01 12:12:48','深圳',35,0,'2017-10-01 
10:00:15',100,3,3),\
(10004,'2017-10-03','2017-10-03 12:38:20','深圳',35,0,'2017-10-03 
10:20:22',11,6,6);

3)查看表

select * from test_db.example_site_visit2;

存储的数据,和导入数据完全一样,没有发生任何聚合。这是因为,这批数据中,因为加入了 timestamp 列,所有行的 Key 都不完全相同。也就是说,只要保证导入的数据中,每一行的 Key 都不完全相同,那么即使在聚合模型下,Doris 也可以保存完整的明细数据。

4.3.5.1.3 示例三:导入数据与已有数据聚合

1)往实例一中继续插入数据

insert into test_db.example_site_visit values(10004,'2017-10-03','
深圳',35,0,'2017-10-03 11:22:00',null,44,19,19),\
(10005,'2017-10-03','长沙',29,1,'2017-10-03 18:11:02','2017-10-03 
18:11:02',3,1,1);

2)查看表

select * from test_db.example_site_visit;

可以看到,用户 10004 的已有数据和新导入的数据发生了聚合。同时新增了 10005 用户的数据。

4.3.5.2 Uniq 模型

在某些多维分析场景下,用户更关注的是如何保证 Key 的唯一性,即如何获得 Primary Key 唯一性约束。因此,我们引入了 Uniq 的数据模型。该模型本质上是聚合模型的一个特例,也是一种简化的表结构表示方式。
1)建表

CREATE TABLE IF NOT EXISTS test_db.user
(
 `user_id` LARGEINT NOT NULL COMMENT "用户 id",
 `username` VARCHAR(50) NOT NULL COMMENT "用户昵称",
 `city` VARCHAR(20) COMMENT "用户所在城市",
 `age` SMALLINT COMMENT "用户年龄",
 `sex` TINYINT COMMENT "用户性别",
 `phone` LARGEINT COMMENT "用户电话",
 `address` VARCHAR(500) COMMENT "用户地址",
 `register_time` DATETIME COMMENT "用户注册时间"
)
UNIQUE KEY(`user_id`, `username`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 10;

2)插入数据

insert into test_db.user values\
(10000,'wuyanzu',' 北 京 ',18,0,12345678910,' 北 京 朝 阳 区 ','2017-10-01 
07:00:00'),\
(10000,'wuyanzu',' 北 京 ',19,0,12345678910,' 北 京 朝 阳 区 ','2017-10-01 
07:00:00'),\
(10000,'zhangsan','北京',20,0,12345678910,'北京海淀区','2017-11-15 
06:10:20');

3)查询表

select * from test_db.user;

Uniq 模型完全可以用聚合模型中的 REPLACE 方式替代。其内部的实现方式和数据存储方式也完全一样.

4.3.5.3 Duplicate 模型

在某些多维分析场景下,数据既没有主键,也没有聚合需求。Duplicate 数据模型可以满足这类需求。数据完全按照导入文件中的数据进行存储,不会有任何聚合。即使两行数据完全相同,也都会保留。 而在建表语句中指定的 DUPLICATE KEY,只是用来指明底层数据按照那些列进行排序。
1)建表

CREATE TABLE IF NOT EXISTS test_db.example_log
(
 `timestamp` DATETIME NOT NULL COMMENT "日志时间",
 `type` INT NOT NULL COMMENT "日志类型",
 `error_code` INT COMMENT "错误码",
 `error_msg` VARCHAR(1024) COMMENT "错误详细信息",
 `op_id` BIGINT COMMENT "负责人 id",
 `op_time` DATETIME COMMENT "处理时间"
)
DUPLICATE KEY(`timestamp`, `type`)
DISTRIBUTED BY HASH(`timestamp`) BUCKETS 10;

2)插入数据

insert into test_db.example_log values\
('2017-10-01 08:00:05',1,404,'not found page', 101, '2017-10-01 
08:00:05'),\
('2017-10-01 08:00:05',1,404,'not found page', 101, '2017-10-01 
08:00:05'),\
('2017-10-01 08:00:05',2,404,'not found page', 101, '2017-10-01 
08:00:06'),\
('2017-10-01 08:00:06',2,404,'not found page', 101, '2017-10-01 
08:00:07');

3)查看表

select * from test_db.example_log;

4.3.5.4 数据模型的选择建议

因为数据模型在建表时就已经确定,且无法修改。所以,选择一个合适的数据模型非常重要。
(1)Aggregate 模型可以通过预聚合,极大地降低聚合查询时所需扫描的数据量和查询的计算量,非常适合有固定模式的报表类查询场景。但是该模型对 count(*) 查询很不友好。同时因为固定了 Value 列上的聚合方式,在进行其他类型的聚合查询时,需要考虑语意正确性。
(2)Uniq 模型针对需要唯一主键约束的场景,可以保证主键唯一性约束。但是无法利用 ROLLUP 等预聚合带来的查询优势(因为本质是 REPLACE,没有 SUM 这种聚合方式)。
(3)Duplicate 适合任意维度的 Ad-hoc 查询。虽然同样无法利用预聚合的特性,但是不受聚合模型的约束,可以发挥列存模型的优势(只读取相关列,而不需要读取所有 Key 列)
3.5.5 聚合模型的局限性
这里我们针对 Aggregate 模型(包括 Uniq 模型),来介绍下聚合模型的局限性。
在聚合模型中,模型对外展现的,是最终聚合后的数据。也就是说,任何还未聚合的数据(比如说两个不同导入批次的数据),必须通过某种方式,以保证对外展示的一致性。我们举例说明。
假设表结构如下:

ColumnName Type AggregationType Comment
user_id LARGEINT 用户 id
date DATE 数据灌入日期
cost BIGINT SUM 用户总消费

假设存储引擎中有如下两个已经导入完成的批次的数据:
batch 1

user_id date cost
10001 2017-11-20 50
10002 2017-11-21 39

batch 2

user_id date cost
10001 2017-11-20 1
10001 2017-11-21 5
10003 2017-11-22 22

可以看到,用户 10001 分属在两个导入批次中的数据还没有聚合。但是为了保证用户只能查询到如下最终聚合后的数据:

user_id date cost
10001 2017-11-20 51
10001 2017-11-21 5
10002 2017-11-21 39
10003 2017-11-22 22

在查询引擎中加入了聚合算子,来保证数据对外的一致性。

另外,在聚合列(Value)上,执行与聚合类型不一致的聚合类查询时,要注意语意。比如我们在如上示例中执行如下查询:

SELECT MIN(cost) FROM table;

得到的结果是 5,而不是 1。

同时,这种一致性保证,在某些查询中,会极大的降低查询效率。

我们以最基本的 count(*) 查询为例:

SELECT COUNT(*) FROM table;

在其他数据库中,这类查询都会很快的返回结果。因为在实现上,我们可以通过如“导入时对行进行计数,保存 count 的统计信息”,或者在查询时“仅扫描某一列数据,获得 count值”的方式,只需很小的开销,即可获得查询结果。但是在 Doris 的聚合模型中,这种查询开销非常大。

上面的例子,select count(*) from table; 的正确结果应该为 4。但如果我们只扫描 user_id 这一列,如果加上查询时聚合,最终得到的结果是 3(10001, 10002, 10003)。而如果不加查询时聚合,则得到的结果是 5(两批次一共 5 行数据)。可见这两个结果都是不对的。

为了得到正确的结果,我们必须同时读取 user_id 和 date 这两列的数据,再加上查询时聚合,才能返回 4 这个正确的结果。也就是说,在 count() 查询中,Doris 必须扫描所有的AGGREGATE KEY 列(这里就是 user_id 和 date),并且聚合后,才能得到语意正确的结果。当聚合列非常多时,count()查询需要扫描大量的数据。

因此,当业务上有频繁的 count() 查询时,我们建议用户通过增加一个值恒为 1 的,聚合类型为 SUM 的列来模拟 count()。如刚才的例子中的表结构,我们修改如下:

ColumnName Type AggregateType Comment
user_id BIGINT 用户 id
date DATE 数据灌入日期
cost BIGINT SUM 用户总消费
count BIGINT SUM 用于计算 count

增加一个 count 列,并且导入数据中,该列值恒为 1。则 select count() from table; 的结果等价于 select sum(count) from table;。而后者的查询效率将远高于前者。不过这种方式也有使用限制,就是用户需要自行保证,不会重复导入 AGGREGATE KEY 列都相同的行。否则,select sum(count) from table; 只能表述原始导入的行数,而不是 select count() from table; 的语义。

另一种方式,就是 将如上的 count 列的聚合类型改为 REPLACE,且依然值恒为 1。那么 select sum(count) from table; 和 select count(*) from table; 的结果将是一致的。并且这种方式,没有导入重复行的限制。

4.3.6 动态分区

动态分区是在 Doris 0.12 版本中引入的新功能。旨在对表级别的分区实现生命周期管理(TTL),减少用户的使用负担。

目前实现了动态添加分区及动态删除分区的功能。动态分区只支持 Range 分区。

4.3.6.1 原理

在某些使用场景下,用户会将表按照天进行分区划分,每天定时执行例行任务,这时需要使用方手动管理分区,否则可能由于使用方没有创建分区导致数据导入失败,这给使用方带来了额外的维护成本。

通过动态分区功能,用户可以在建表时设定动态分区的规则。FE 会启动一个后台线程,根据用户指定的规则创建或删除分区。用户也可以在运行时对现有规则进行变更。

4.3.6.2 使用方式

动态分区的规则可以在建表时指定,或者在运行时进行修改。当前仅支持对单分区列的分区表设定动态分区规则。
建表时指定:

CREATE TABLE tbl1
(...)
PROPERTIES
(
 "dynamic_partition.prop1" = "value1",
 "dynamic_partition.prop2" = "value2",
 ...
)

运行时修改

ALTER TABLE tbl1 SET
(
 "dynamic_partition.prop1" = "value1",
 "dynamic_partition.prop2" = "value2",
  ...
)

4.3.6.3 动态分区规则参数

4.3.6.3.1 主要参数

动态分区的规则参数都以 dynamic_partition. 为前缀:

dynamic_partition.enable 是否开启动态分区特性,可指定 true 或 false,默认为 true
dynamic_partition.time_unit 动态分区调度的单位,可指定 HOUR、DAY、WEEK、MONTH。HOUR,后缀格式为 yyyyMMddHH,分区列数据类型不能为DATE。DAY,后缀格式为 yyyyMMdd。WEEK,后缀格式为 yyyy_ww。即当前日期属于这一年的第几周。MONTH,后缀格式为 yyyyMM。
dynamic_partition.time_zone 动态分区的时区,如果不填写,则默认为当前机器的系统的时区
dynamic_partition.start 动态分区的起始偏移,为负数。根据 time_unit 属性的不同,以当天(星期/月)为基准,分区范围在此偏移之前的分区将会被删除。如果不填写默认值为 Interger.Min_VALUE 即-2147483648,即不删除历史分区
dynamic_partition.end 动态分区的结束偏移,为正数。根据 time_unit 属性的不同,以当天(星期/月)为基准,提前创建对应范围的分区
dynamic_partition.prefix 动态创建的分区名前缀
dynamic_partition.buckets 动态创建的分区所对应分桶数量
dynamic_partition.replication_num 动态创建的分区所对应的副本数量,如果不填写,则默认为该表创建时指定的副本数量。
dynamic_partition.start_day_of_week 当 time_unit 为 WEEK 时,该参数用于指定每周的起始点。取值为 1 到 7。其中 1 表示周一,7 表示周日。默认为 1,即表示每周以周一为起始点
dynamic_partition.start_day_of_month 当 time_unit 为 MONTH 时,该参数用于指定每月的起始日期。取值为 1 到 28。其中 1 表示每月 1 号,28 表示每月 28 号。默认为 1,即表示每月以 1 号位起始点。暂不支持以 29、30、31 号为起始日,以避免因闰年或闰月带来的歧义
4.3.6.3.2 创建历史分区的参数

⚫ dynamic_partition.create_history_partition
默认为 false。当置为 true 时,Doris 会自动创建所有分区,当期望创建的分区个数大于 max_dynamic_partition_num 值时,操作将被禁止。当不指定 start 属性时,该参数不生效。
⚫ dynamic_partition.history_partition_num
当 create_history_partition 为 true 时,该参数用于指定创建历史分区数量。默认值为 -1, 即未设置。

⚫ dynamic_partition.hot_partition_num
指定最新的多少个分区为热分区。对于热分区,系统会自动设置其 storage_medium 参数为 SSD,并且设置 storage_cooldown_time。

hot_partition_num 是往前 n 天和未来所有分区

我们举例说明。假设今天是 2021-05-20,按天分区,动态分区的属性设置为:
hot_partition_num=2, end=3, start=-3。则系统会自动创建以下分区,并且设置 storage_medium 和 storage_cooldown_time 参数:

p20210517 : ["2021-05-17", "2021-05-18") storage_medium=HDD 
storage_cooldown_time=9999-12-31 23:59:59
p20210518 : ["2021-05-18", "2021-05-19") storage_medium=HDD 
storage_cooldown_time=9999-12-31 23:59:59
p20210519 : ["2021-05-19", "2021-05-20") storage_medium=SSD 
storage_cooldown_time=2021-05-21 00:00:00
p20210520 : ["2021-05-20", "2021-05-21") storage_medium=SSD 
storage_cooldown_time=2021-05-22 00:00:00
p20210521 : ["2021-05-21", "2021-05-22") storage_medium=SSD 
storage_cooldown_time=2021-05-23 00:00:00
p20210522 : ["2021-05-22", "2021-05-23") storage_medium=SSD 
storage_cooldown_time=2021-05-24 00:00:00
p20210523 : ["2021-05-23", "2021-05-24") storage_medium=SSD 
storage_cooldown_time=2021-05-25 00:00:00

⚫ dynamic_partition.reserved_history_periods
需要保留的历史分区的时间范围。当 dynamic_partition.time_unit 设置为
“DAY/WEEK/MONTH” 时,需要以 [yyyy-MM-dd,yyyy-MM-dd],[…,…] 格式进行设置。当dynamic_partition.time_unit 设置为 “HOUR” 时,需要以 [yyyy-MM-dd HH:mm:ss,yyyyMM-dd HH:mm:ss],[…,…] 的格式来进行设置。如果不设置,默认为 “NULL”。

我们举例说明。假设今天是 2021-09-06,按天分类,动态分区的属性设置为:

time_unit=“DAY/WEEK/MONTH”, \ end=3, \ start=-3,
reserved_history_periods=“[2020-06-01,2020-06-20],[2020-10-
31,2020-11-15]”。

则系统会自动保留:

[“2020-06-01”,“2020-06-20”], [“2020-10-31”,“2020-11-15”]

或者

time_unit=“HOUR”, \ end=3, \ start=-3,
reserved_history_periods=“[2020-06-01 00:00:00,2020-06-01 03:00:00]”.

则系统会自动保留:

[“2020-06-01 00:00:00”,“2020-06-01 03:00:00”]

这两个时间段的分区。其中,reserved_history_periods 的每一个 […,…] 是一对设置项,两者需要同时被设置,且第一个时间不能大于第二个时间``。

4.3.6.3.3 创建历史分区规则

假设需要创建的历史分区数量为 expect_create_partition_num,根据不同的设置具体数量如下:
(1)create_history_partition = true
① dynamic_partition.history_partition_num 未设置,即 -1.
则 expect_create_partition_num = end - start;
② dynamic_partition.history_partition_num 已设置
则 expect_create_partition_num = end - max(start, -histoty_partition_num);
(2)create_history_partition = false
不会创建历史分区,expect_create_partition_num = end - 0;
(3)当 expect_create_partition_num > max_dynamic_partition_num(默认 500)时,禁止创建过多分区。

4.3.6.3.4 创建历史分区举例

假设今天是 2021-05-20,按天分区,动态分区的属性设置为:create_history_partition=true, end=3, start=-3, history_partition_num=1,则系统会自动创建以下分区:
p20210519
p20210520
p20210521
p20210522
p20210523
history_partition_num=5,其余属性与 1 中保持一直,则系统会自动创建以下分区:
p20210517
p20210518
p20210519
p20210520
p20210521
p20210522
p20210523
history_partition_num=-1 即不设置历史分区数量,其余属性与 1 中保持一直,则系统
会自动创建以下分区:
p20210517
p20210518
p20210519
p20210520
p20210521
p20210522
p20210523

4.3.6.3.5 注意事项

动 态 分 区 使 用 过 程 中 , 如 果 因 为 一 些 意 外 情 况 导 致 dynamic_partition.start 和
dynamic_partition.end 之间的某些分区丢失,那么当前时间与 dynamic_partition.end 之间的
丢失分区会被重新创建,dynamic_partition.start 与当前时间之间的丢失分区不会重新创建。

4.3.6.4 示例

1)创建动态分区表
分区列 time 类型为 DATE,创建一个动态分区规则。按天分区,只保留最近 7 天的分
区,并且预先创建未来 3 天的分区。

create table student_dynamic_partition1
(id int,
time date,
name varchar(50),
age int
)
duplicate key(id,time)
PARTITION BY RANGE(time)()
DISTRIBUTED BY HASH(id) buckets 10
PROPERTIES(
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "DAY",
"dynamic_partition.start" = "-7",
"dynamic_partition.end" = "3",
"dynamic_partition.prefix" = "p",
"dynamic_partition.buckets" = "10",
"replication_num" = "1"
);

2)查看动态分区表调度情况

SHOW DYNAMIC PARTITION TABLES;

⚫ LastUpdateTime: 最后一次修改动态分区属性的时间
⚫ LastSchedulerTime: 最后一次执行动态分区调度的时间
⚫ State: 最后一次执行动态分区调度的状态
⚫ LastCreatePartitionMsg: 最后一次执行动态添加分区调度的错误信息
⚫ LastDropPartitionMsg: 最后一次执行动态删除分区调度的错误信息
3)查看表的分区

SHOW PARTITIONS FROM student_dynamic_partition1;

4)插入测试数据,可以全部成功(修改成对应时间)

insert into student_dynamic_partition1 values(1,'2022-03-3111:00:00','name1',18);
insert into student_dynamic_partition1 values(1,'2022-04-01
11:00:00','name1',18);
insert into student_dynamic_partition1 values(1,'2022-04-02 
11:00:00','name1',18);

5)设置创建历史分区

ALTER TABLE student_dynamic_partition1 SET 
("dynamic_partition.create_history_partition" = "true");

查看分区情况

SHOW PARTITIONS FROM student_dynamic_partition1;

6)动态分区表与手动分区表相互转换
对于一个表来说,动态分区和手动分区可以自由转换,但二者不能同时存在,有且只有一种状态。
(1)手动分区转换为动态分区
如果一个表在创建时未指定动态分区,可以通过 ALTER TABLE 在运行时修改动态分区相关属性来转化为动态分区,具体示例可以通过 HELP ALTER TABLE 查看。
注意:如果已设定 dynamic_partition.start,分区范围在动态分区起始偏移之前的历史分区将会被删除。
(2)动态分区转换为手动分区

ALTER TABLE tbl_name SET ("dynamic_partition.enable" = "false") 

关闭动态分区功能后,Doris 将不再自动管理分区,需要用户手动通过 ALTER TABLE 的方式创建或删除分区。

4.3.7 Rollup

ROLLUP 在多维分析中是“上卷”的意思,即将数据按某种指定的粒度进行进一步聚合。

4.3.7.1 基本概念

在 Doris 中,我们将用户通过建表语句创建出来的表称为 Base 表(Base Table)。Base 表中保存着按用户建表语句指定的方式存储的基础数据。

在 Base 表之上,我们可以创建任意多个 ROLLUP 表。这些 ROLLUP 的数据是基于 Base 表产生的,并且在物理上是独立存储的。

ROLLUP 表的基本作用,在于在 Base 表的基础上,获得更粗粒度的聚合数据。

4.3.7.2 Aggregate 和 Uniq 模型中的 ROLLUP

因为 Uniq 只是 Aggregate 模型的一个特例,所以这里我们不加以区别。
1)以 4.3.5.1.2 中创建的 example_site_visit2 表为例。
(1)查看表的结构信息

desc example_site_visit2 all;

(2)比如需要查看某个用户的总消费,那么可以建立一个只有 user_id 和 cost 的 rollup

alter table example_site_visit2 add rollup 
rollup_cost_userid(user_id,cost);

(3)查看表的结构信息

desc example_site_visit2 all;

(4)然后可以通过 explain 查看执行计划,是否使用到了 rollup

explain SELECT user_id, sum(cost) FROM example_site_visit2 GROUP BY 
user_id;

Doris 会自动命中这个 ROLLUP 表,从而只需扫描极少的数据量,即可完成这次聚合查询。
(5)通过命令查看完成状态

SHOW ALTER TABLE ROLLUP;

2)示例 2:获得不同城市,不同年龄段用户的总消费、最长和最短页面驻留时间
(1)创建 ROLLUP

alter table example_site_visit2 add rollup 
rollup_city_age_cost_maxd_mind(city,age,cost,max_dwell_time,min_d
well_time);

(2)查看 rollup 使用

explain SELECT city, age, sum(cost), max(max_dwell_time), 
min(min_dwell_time) FROM example_site_visit2 GROUP BY city, age;
explain SELECT city, sum(cost), max(max_dwell_time), 
min(min_dwell_time) FROM example_site_visit2 GROUP BY city;
explain SELECT city, age, sum(cost), min(min_dwell_time) FROM 
example_site_visit2 GROUP BY city, age;

(3)通过命令查看完成状态

SHOW ALTER TABLE ROLLUP;

4.3.7.3 Duplicate 模型中的 ROLLUP

因为 Duplicate 模型没有聚合的语意。所以该模型中的 ROLLUP,已经失去了“上卷”
这一层含义。而仅仅是作为调整列顺序,以命中前缀索引的作用。下面详细介绍前缀索引,
以及如何使用 ROLLUP 改变前缀索引,以获得更好的查询效率。

4.3.7.3.1 前缀索引

不同于传统的数据库设计,Doris 不支持在任意列上创建索引。Doris 这类 MPP 架构的 OLAP 数据库,通常都是通过提高并发,来处理大量数据的。
本质上,Doris 的数据存储在类似 SSTable(Sorted String Table)的数据结构中。该结构是一种有序的数据结构,可以按照指定的列进行排序存储。在这种数据结构上,以排序列作为条件进行查找,会非常的高效。

在 Aggregate、Uniq 和 Duplicate 三种数据模型中。底层的数据存储,是按照各自建表语句中,AGGREGATE KEY、UNIQ KEY 和 DUPLICATE KEY 中指定的列进行排序存储的。而前缀索引,即在排序的基础上,实现的一种根据给定前缀列,快速查询数据的索引方式。

我们将一行数据的前 36 个字节 作为这行数据的前缀索引。当遇到 VARCHAR 类型时,前缀索引会直接截断。举例说明:
1)以下表结构的前缀索引为 user_id(8 Bytes) + age(4 Bytes) + message(prefix 20 Bytes)。

ColumnName Type
user_id BIGINT
age INT
message VARCHAR(100)
max_dwell_time DATETIME
min_dwell_time DATETIME

2)以下表结构的前缀索引为 user_name(20 Bytes)。即使没有达到 36 个字节,因为遇到VARCHAR,所以直接截断,不再往后继续。

ColumnName Type
user_name VARCHAR(20)
age INT
message VARCHAR(100)
max_dwell_time DATETIME
min_dwell_time DATETIME

3)当我们的查询条件,是前缀索引的前缀时,可以极大的加快查询速度。比如在第一个例子中,我们执行如下查询:

SELECT * FROM table WHERE user_id=1829239 and age=20

该查询的效率会远高于如下查询:

SELECT * FROM table WHERE age=20

所以在建表时,正确的选择列顺序,能够极大地提高查询效率。

4.3.7.3.2 ROLLUP 调整前缀索引

因为建表时已经指定了列顺序,所以一个表只有一种前缀索引。这对于使用其他不能命中前缀索引的列作为条件进行的查询来说,效率上可能无法满足需求。因此,我们可以通过创建 ROLLUP 来人为的调整列顺序。举例说明。
Base 表结构如下:

ColumnName Type
user_id BIGINT
age INT
message VARCHAR(100)
max_dwell_time DATETIME
min_dwell_time DATETIME

我们可以在此基础上创建一个 ROLLUP 表:

ColumnName Type
age INT
user_id BIGINT
message VARCHAR(100)
max_dwell_time DATETIME
min_dwell_time DATETIME

可以看到,ROLLUP 和 Base 表的列完全一样,只是将 user_id 和 age 的顺序调换了。那么当我们进行如下查询时:

SELECT * FROM table where age=20 and message LIKE "%error%";

会优先选择 ROLLUP 表,因为 ROLLUP 的前缀索引匹配度更高。

4.3.7.4 ROLLUP 的几点说明

⚫ ROLLUP 最根本的作用是提高某些查询的查询效率(无论是通过聚合来减少数据量,还是修改列顺序以匹配前缀索引)。因此 ROLLUP 的含义已经超出了“上卷”的范围。这也是为什么在源代码中,将其命名为 Materialized Index(物化索引)的原因。
⚫ ROLLUP 是附属于 Base 表的,可以看做是 Base 表的一种辅助数据结构。用户可以在 Base 表的基础上,创建或删除 ROLLUP,但是不能在查询中显式的指定查询某ROLLUP。是否命中 ROLLUP 完全由 Doris 系统自动决定。
⚫ ROLLUP 的数据是独立物理存储的。因此,创建的 ROLLUP 越多,占用的磁盘空间也就越大。同时对导入速度也会有影响(导入的 ETL 阶段会自动产生所有
ROLLUP 的数据),但是不会降低查询效率(只会更好)。
⚫ ROLLUP 的数据更新与 Base 表是完全同步的。用户无需关心这个问题。
⚫ ROLLUP 中列的聚合方式,与 Base 表完全相同。在创建 ROLLUP 无需指定,也不能修改。
⚫ 查询能否命中 ROLLUP 的一个必要条件(非充分条件)是,查询所涉及的所有列(包括 select list 和 where 中的查询条件列等)都存在于该 ROLLUP 的列中。否则,查询只能命中 Base 表。
⚫ 某些类型的查询(如 count(*))在任何条件下,都无法命中 ROLLUP。具体参见接下来的聚合模型的局限性一节。
⚫ 可以通过 EXPLAIN your_sql; 命令获得查询执行计划,在执行计划中,查看是否命中 ROLLUP。
⚫ 可以通过 DESC tbl_name ALL; 语句显示 Base 表和所有已创建完成的 ROLLUP。

4.3.8 物化视图

物化视图就是包含了查询结果的数据库对象,可能是对远程数据的本地 copy,也可能是一个表或多表 join 后结果的行或列的子集,也可能是聚合后的结果。说白了,就是预先存储查询结果的一种数据库对象。

在 Doris 中的物化视图,就是查询结果预先存储起来的特殊的表。
物化视图的出现主要是为了满足用户,既能对原始明细数据的任意维度分析,也能快速的对固定维度进行分析查询。

4.3.8.1 适用场景

⚫ 分析需求覆盖明细数据查询以及固定维度查询两方面。
⚫ 查询仅涉及表中的很小一部分列或行。
⚫ 查询包含一些耗时处理操作,比如:时间很久的聚合操作等。
⚫ 查询需要匹配不同前缀索引。

4.3.8.2 优势

⚫ 对于那些经常重复的使用相同的子查询结果的查询性能大幅提升。
⚫ Doris 自动维护物化视图的数据,无论是新的导入,还是删除操作都能保证 base 表和物化视图表的数据一致性。无需任何额外的人工维护成本。
⚫ 查询时,会自动匹配到最优物化视图,并直接从物化视图中读取数据。
自动维护物化视图的数据会造成一些维护开销,会在后面的物化视图的局限性中展开说明。

4.3.8.3 物化视图 VS Rollup

在没有物化视图功能之前,用户一般都是使用 Rollup 功能通过预聚合方式提升查询效率的。但是 Rollup 具有一定的局限性,他不能基于明细模型做预聚合。
物化视图则在覆盖了 Rollup 的功能的同时,还能支持更丰富的聚合函数。所以物化视图其实是 Rollup 的一个超集。
也就是说,之前 ALTER TABLE ADD ROLLUP 语法支持的功能现在均可以通过
CREATE MATERIALIZED VIEW 实现。

4.3.8.4 物化视图原理

Doris 系统提供了一整套对物化视图的 DDL 语法,包括创建,查看,删除。DDL 的语法和 PostgreSQL, Oracle 都是一致的。但是 Doris 目前创建物化视图只能在单表操作,不支持 join.

4.3.8.4.1 创建物化视图

首先要根据查询语句的特点来决定创建一个什么样的物化视图。并不是说物化视图定义和某个查询语句一模一样就最好。这里有两个原则:
(1)从查询语句中抽象出,多个查询共有的分组和聚合方式作为物化视图的定义。
(2)不需要给所有维度组合都创建物化视图。
首先第一个点,一个物化视图如果抽象出来,并且多个查询都可以匹配到这张物化视图。
这种物化视图效果最好。因为物化视图的维护本身也需要消耗资源。
如果物化视图只和某个特殊的查询很贴合,而其他查询均用不到这个物化视图。则会导致这张物化视图的性价比不高,既占用了集群的存储资源,还不能为更多的查询服务。
所以用户需要结合自己的查询语句,以及数据维度信息去抽象出一些物化视图的定义。
第二点就是,在实际的分析查询中,并不会覆盖到所有的维度分析。所以给常用的维度组合创建物化视图即可,从而到达一个空间和时间上的平衡。
通过下面命令就可以创建物化视图了。创建物化视图是一个异步的操作,也就是说用户成功提交创建任务后,Doris 会在后台对存量的数据进行计算,直到创建成功。
具体的语法可以通过下面命令查看:HELP CREATE MATERIALIZED VIEW
这里以一个销售记录表为例:
ここに画像の説明を挿入
比如我们有一张销售记录明细表,存储了每个交易的时间,销售员,销售门店,和金额。
提交完创建物化视图的任务后,Doris 就会异步在后台生成物化视图的数据,构建物化视图。
在构建期间,用户依然可以正常的查询和导入新的数据。创建任务会自动处理当前的存量数据和所有新到达的增量数据,从而保持和 base 表的数据一致性。用户不需关心一致性问题.

4.3.8.4.2 查询

ここに画像の説明を挿入
物化视图创建完成后,用户的查询会根据规则自动匹配到最优的物化视图。
比如我们有一张销售记录明细表,并且在这个明细表上创建了三张物化视图。一个存储了不同时间不同销售员的售卖量,一个存储了不同时间不同门店的销售量,以及每个销售员的总销售量。
当查询 7 月 19 日,各个销售员都买了多少钱的话。就可以匹配 mv_1 物化视图。直接对 mv_1 的数据进行查询。

4.3.8.4.3 查询自动匹配

ここに画像の説明を挿入
物化视图的自动匹配分为下面两个步骤:
(1)根据查询条件删选出一个最优的物化视图:这一步的输入是所有候选物化视图表的元数据,根据查询的条件从候选集中输出最优的一个物化视图
(2)根据选出的物化视图对查询进行改写:这一步是结合上一步选择出的最优物化视图,进行查询的改写,最终达到直接查询物化视图的目的。
ここに画像の説明を挿入
其中 bitmap 和 hll 的聚合函数在查询匹配到物化视图后,查询的聚合算子会根据物化视图的表结构进行一个改写。详细见实例 2

4.3.8.4.4 最优路径选择

ここに画像の説明を挿入
这里分为两个步骤:
(1)对候选集合进行一个过滤。只要是查询的结果能从物化视图数据计算(取部分行,部分列,或部分行列的聚合)出都可以留在候选集中,过滤完成后候选集合大小>=1.
(2)从候选集合中根据聚合程度,索引等条件选出一个最优的也就是查询花费最少物化视图。
这里再举一个相对复杂的例子,来体现这个过程:
ここに画像の説明を挿入
候选集过滤目前分为 4 层,每一层过滤后去除不满足条件的物化视图。
比如查询 7 月 19 日,各个销售员都买了多少钱,候选集中包括所有的物化视图以及 base表共 4 个:
第一层过滤先判断查询 where 中的谓词涉及到的数据是否能从物化视图中得到。也就是销售时间列是否在表中存在。由于第三个物化视图中根本不存在销售时间列。所以在这一层过滤中,mv_3 就被淘汰了。

第二层是过滤查询的分组列是否为候选集的分组列的子集。也就是销售员 id 是否为表中分组列的子集。由于第二个物化视图中的分组列并不涉及销售员 id。所以在这一层过滤中,mv_2 也被淘汰了。

第三层过滤是看查询的聚合列是否为候选集中聚合列的子集。也就是对销售额求和是否能从候选集的表中聚合得出。这里 base 表和物化视图表均满足标准。
最后一层是过滤看查询需要的列是否存在于候选集合的列中。由于候选集合中的表均满足标准,所以最终候选集合中的表为 销售明细表,以及 mv_1,这两张。

ここに画像の説明を挿入
候选集过滤完后输出一个集合,这个集合中的所有表都能满足查询的需求。但每张表的查询效率都不同。这时候就需要再这个集合根据前缀索引是否能匹配到,以及聚合程度的高低来选出一个最优的物化视图。
从表结构中可以看出,base 表的销售日期列是一个非排序列,而物化视图表的日期是一个排序列,同时聚合程度上 mv_1 表明显比 base 表高。所以最后选择出 mv_1作为该查询的最优匹配。
ここに画像の説明を挿入
最后再根据选择出的最优解,改写查询。
刚才的查询选中 mv_1 后,将查询改写为从 mv_1 中读取数据,过滤出日志为 7 月 19 日的 mv_1 中的数据然后返回即可。

4.3.8.4.5 查询改写

ここに画像の説明を挿入

有些情况下的查询改写还会涉及到查询中的聚合函数的改写。
比如业务方经常会用到 count distinct 对 PV UV 进行计算。
例如;
广告点击明细记录表中存放哪个用户点击了什么广告,从什么渠道点击的,以及点击的时间。并且在这个 base 表基础上构建了一个物化视图表,存储了不同广告不同渠道的用户bitmap 值。
由于 bitmap union 这种聚合方式本身会对相同的用户 user id 进行一个去重聚合。当用户查询广告在 web 端的 uv 的时候,就可以匹配到这个物化视图。匹配到这个物化视图表后就需要对查询进行改写,将之前的对用户 id 求 count(distinct) 改为对物化视图中 bitmap union列求 count。
所以最后查询取物化视图的第一和第三行求 bitmap 聚合中有几个值。

4.3.8.4.6 使用及限制

ここに画像の説明を挿入
(1)目前支持的聚合函数包括,常用的 sum,min,max count,以及计算 pv ,uv, 留存率,等常用的去重算法 hll_union,和用于精确去重计算 count(distinct)的算法bitmap_union。
(2)物化视图的聚合函数的参数不支持表达式仅支持单列,比如: sum(a+b)不支持。
(3)使用物化视图功能后,由于物化视图实际上是损失了部分维度数据的。所以对表的 DML 类型操作会有一些限制:
如果表的物化视图 key 中不包含删除语句中的条件列,则删除语句不能执行。
比如想要删除渠道为 app 端的数据,由于存在一个物化视图并不包含渠道这个字段,则这个删除不能执行,因为删除在物化视图中无法被执行。这时候你只能把物化视图先删除,然后删除完数据后,重新构建一个新的物化视图。
(4)单表上过多的物化视图会影响导入的效率:导入数据时,物化视图和 base 表数据是同步更新的,如果一张表的物化视图表超过 10 张,则有可能导致导入速度很慢。这就像单次导入需要同时导入 10 张表数据是一样的。
(5)相同列,不同聚合函数,不能同时出现在一张物化视图中,比如:select sum(a), min(a) from table 不支持。
(6)物化视图针对 Unique Key 数据模型,只能改变列顺序,不能起到聚合的作用,所以在 Unique Key 模型上不能通过创建物化视图的方式对数据进行粗粒度聚合操作.

4.3.8.5 案例演示

4.3.8.5.1 案例一

1)创建一个 Base 表

create table sales_records(
record_id int,
 seller_id int,
 store_id int,
 sale_date date,
 sale_amt bigint
) 
distributed by hash(record_id) 
properties("replication_num" = "1");

插入数据

insert into sales_records values(1,2,3,'2020-02-02',10);

2)基于这个 Base 表的数据提交一个创建物化视图的任务

create materialized view store_amt as 
select store_id, sum(sale_amt) 
from sales_records 
group by store_id;

3)检查物化视图是否构建完成
由于创建物化视图是一个异步的操作,用户在提交完创建物化视图任务后,需要异步的
通过命令检查物化视图是否构建完成。
SHOW ALTER TABLE MATERIALIZED VIEW FROM test_db; (Version 0.13)
查看 Base 表的所有物化视图

desc sales_records all;

4)检验当前查询是否匹配到了合适的物化视图

EXPLAIN SELECT store_id, sum(sale_amt) FROM sales_records GROUP BY 
store_id;

5)删除物化视图语法

DROP MATERIALIZED VIEW 物化视图名 on Base 表名;
4.3.8.5.2 案例二:计算广告的 pv、uv

假设用户的原始广告点击数据存储在 Doris,那么针对广告 PV, UV 查询就可以通过创建 bitmap_union 的物化视图来提升查询速度。
1)创建 base 表

create table advertiser_view_record(
time date, 
advertiser varchar(10), 
channel varchar(10), 
user_id int
) 
distributed by hash(time) 
properties("replication_num" = "1");

插入数据

insert into advertiser_view_record values('2020-02-
02','a','app',123);

2)创建物化视图

create materialized view advertiser_uv as 
select advertiser, channel, bitmap_union(to_bitmap(user_id)) 
from advertiser_view_record 
group by advertiser, channel;

在 Doris 中,count(distinct) 聚合的结果和 bitmap_union_count 聚合的结果是完全一致的。而 bitmap_union_count 等于 bitmap_union 的结果求 count,所以如果查询中涉及到count(distinct) 则通过创建带 bitmap_union 聚合的物化视图方可加快查询。
因为本身 user_id 是一个 INT 类型,所以在 Doris 中需要先将字段通过函数 to_bitmap 转换为 bitmap 类型然后才可以进行 bitmap_union 聚合。
3)查询自动匹配

SELECT advertiser, channel, count(distinct user_id) 
FROM advertiser_view_record 
GROUP BY advertiser, channel;

会自动转换成。

SELECT advertiser, channel, bitmap_union_count(to_bitmap(user_id)) 
FROM advertiser_uv 
GROUP BY advertiser, channel;

4)检验是否匹配到物化视图

explain SELECT advertiser, channel, count(distinct user_id) FROM 
advertiser_view_record GROUP BY advertiser, channel;

在 EXPLAIN 的结果中,首先可以看到 OlapScanNode 的 rollup 属性值为 advertiser_uv。
也就是说,查询会直接扫描物化视图的数据。说明匹配成功。其次对于 user_id 字段求 count(distinct)被改写为求bitmap_union_count(to_bitmap)。也就是通过 bitmap 的方式来达到精确去重的效果。

4.3.8.5.3 案例三

用户的原始表有(k1, k2, k3)三列。其中 k1, k2 为前缀索引列。这时候如果用户查询条件中包含 where k1=1 and k2=2 就能通过索引加速查询。
但是有些情况下,用户的过滤条件无法匹配到前缀索引,比如 where k3=3。则无法通过索引提升查询速度。
创建以 k3 作为第一列的物化视图就可以解决这个问题。
1)查询
explain select record_id,seller_id,store_id from sales_records
where store_id=3;
2)创建物化视图

create materialized view mv_1 as 
select 
 store_id,
 record_id,
 seller_id,
 sale_date,
 sale_amt
from sales_records;

通过上面语法创建完成后,物化视图中既保留了完整的明细数据,且物化视图的前缀索引为 store_id 列。
3)查看表结构

desc sales_records all;

4)查询匹配

explain select record_id,seller_id,store_id from sales_records 
where store_id=3;

这时候查询就会直接从刚才创建的 mv_1 物化视图中读取数据。物化视图对 store_id是存在前缀索引的,查询效率也会提升。

4.3.9 修改表

使用 ALTER TABLE 命令可以对表进行修改,包括 partition 、rollup、schema change、
rename 和 index 五种。语法:

ALTER TABLE [database.]table
alter_clause1[, alter_clause2, ...];

alter_clause 分为 partition 、rollup、schema change、rename 和 index 五种。

4.3.9.1 rename

1)将名为 table1 的表修改为 table2

ALTER TABLE table1 RENAME table2;

2)将表 example_table 中名为 rollup1 的 rollup index 修改为 rollup2

ALTER TABLE example_table RENAME ROLLUP rollup1 rollup2;

3)将表 example_table 中名为 p1 的 partition 修改为 p2

ALTER TABLE example_table RENAME PARTITION p1 p2;

4.3.9.2 partition

1)增加分区, 使用默认分桶方式
现有分区 [MIN, 2013-01-01),增加分区 [2013-01-01, 2014-01-01),

ALTER TABLE example_db.my_table
ADD PARTITION p1 VALUES LESS THAN ("2014-01-01");

2)增加分区,使用新的分桶数

ALTER TABLE example_db.my_table
ADD PARTITION p1 VALUES LESS THAN ("2015-01-01")
DISTRIBUTED BY HASH(k1) BUCKETS 20;

3)增加分区,使用新的副本数

ALTER TABLE example_db.my_table
ADD PARTITION p1 VALUES LESS THAN ("2015-01-01")
("replication_num"="1");

4)修改分区副本数

ALTER TABLE example_db.my_table
MODIFY PARTITION p1 SET("replication_num"="1");

5)批量修改指定分区

ALTER TABLE example_db.my_table
MODIFY PARTITION (p1, p2, p4) SET("in_memory"="true");

6)批量修改所有分区

ALTER TABLE example_db.my_table
MODIFY PARTITION (*) SET("storage_medium"="HDD");

7)删除分区

ALTER TABLE example_db.my_table
DROP PARTITION p1;

8)增加一个指定上下界的分区

ALTER TABLE example_db.my_table
ADD PARTITION p1 VALUES [("2014-01-01"), ("2014-02-01"));

4.3.9.3 rollup

1)创建 index: example_rollup_index,基于 base index(k1,k2,k3,v1,v2)。列式存储。

ALTER TABLE example_db.my_table
ADD ROLLUP example_rollup_index(k1, k3, v1, v2);

2)创建 index: example_rollup_index2,基于 example_rollup_index(k1,k3,v1,v2)

ALTER TABLE example_db.my_table
ADD ROLLUP example_rollup_index2 (k1, v1)
FROM example_rollup_index;

3)创建 index: example_rollup_index3, 基于 base index (k1,k2,k3,v1), 自定义 rollup 超时时间一小时。

ALTER TABLE example_db.my_table
ADD ROLLUP example_rollup_index(k1, k3, v1)
PROPERTIES("timeout" = "3600");

4)删除 index: example_rollup_index2

ALTER TABLE example_db.my_table
DROP ROLLUP example_rollup_index2;

4.3.9.4 表结构变更

使用 ALTER TABLE 命令可以修改表的 Schema,包括如下修改:
⚫ 增加列
⚫ 删除列
⚫ 修改列类型
⚫ 改变列顺序
以增加列为例:
1)我们新增一列 uv,类型为 BIGINT,聚合类型为 SUM,默认值为 0:

ALTER TABLE table1 ADD COLUMN uv BIGINT SUM DEFAULT '0' after pv;

2)提交成功后,可以通过以下命令查看作业进度:

SHOW ALTER TABLE COLUMN;

当作业状态为 FINISHED,则表示作业完成。新的 Schema 已生效。
3)查看新的 Schema

DESC table1;

4)可以使用以下命令取消当前正在执行的作业:

CANCEL ALTER TABLE ROLLUP FROM table1;

5)更多可以参阅: HELP ALTER TABLE
https://doris.apache.org/zh-CN/sql-reference/sql-statements/Data%20Definition/ALTER%20TABLE.html

4.3.10 删除数据(Delete)

Doris 目前可以通过两种方式删除数据:DELETE FROM 语句和 ALTER TABLE DROP
PARTITION 语句。

4.3.10.1 DELETE FROM Statement(条件删除)

delete from 语句类似标准 delete 语法,具体使用可以查看 help delete; 帮助。
语法:

DELETE FROM table_name [PARTITION partition_name]
WHERE
column_name1 op { value | value_list } [ AND column_name2 op { value 
| value_list } ...];

如:
delete from student_kafka where id=1;
注意事项。
(1)该语句只能针对 Partition 级别进行删除。如果一个表有多个 partition 含有需要删除的数据,则需要执行多次针对不同 Partition 的 delete 语句。而如果是没有使用Partition 的表,partition 的名称即表名。
(2)where 后面的条件谓词只能针对 Key 列,并且谓词之间,只能通过 AND 连接。
如果想实现 OR 的语义,需要执行多条 delete。
(3)delete 是一个同步命令,命令返回即表示执行成功。
(4)从代码实现角度,delete 是一种特殊的导入操作。该命令所导入的内容,也是一
个新的数据版本,只是该版本中只包含命令中指定的删除条件。在实际执行查询时,会根据
这些条件进行查询时过滤。所以,不建议大量频繁使用 delete 命令,因为这可能导致查询
效率降低。
(5)数据的真正删除是在 BE 进行数据 Compaction 时进行的。所以执行完 delete 命
令后,并不会立即释放磁盘空间。
(6)delete 命令一个较强的限制条件是,在执行该命令时,对应的表,不能有正在进行的导入任务(包括 PENDING、ETL、LOADING)。而如果有 QUORUM_FINISHED 状态的导入任务,则可能可以执行。
(7) delete には、QUORUM_FINISHED に似た暗黙の状態もあります。つまり、大多数のレプリカでのみ削除が完了した場合、ユーザーにも成功が返されます。ただし、非同期削除ジョブ (Async Delete Job) がバックグラウンドで生成され、残りのコピーの削除が続行されます。この時点で show delete コマンドを使用すると、この種のタスクでは状態列に QUORUM_FINISHED が表示されることがわかります。

4.3.10.2 DROP PARTITION文

このコマンドは、指定されたパーティションを直接削除できます。パーティションは最小の論理的なデータ管理単位であるため、DROP PARTITION コマンドを使用すると、非常に簡単にデータの削除を完了できます。また、このコマンドは負荷やその他の操作によって制限されず、クエリの効率には影響しません。データを削除するための推奨される方法です。
このコマンドは同期コマンドであり、実行が成功すると有効になります。バックグラウンドデータの実際の削除時間は、10分程度遅れる場合があります。

おすすめ

転載: blog.csdn.net/qq_44696532/article/details/128341972