全部產品
Search
文件中心

ApsaraDB for SelectDB:第三步:學習資料庫表設計要點

更新時間:Dec 31, 2025

良好的表結構設計不僅能支援豐富的功能需求,還能大幅提升資料庫系統的效能、可維護性和可擴充性等,因此資料庫的表結構設計至關重要。本文為您介紹在ApsaraDB for SelectDB中,設計表結構時需要重點關注的表屬性,並協助您快速掌握如何根據業務情境選擇合適的表設計,從而更好的滿足業務需求。

重要表屬性概覽

在業務接入SelectDB時,根據業務情境做好重要表屬性的設計,對於構建出能滿足業務需求且高效能、易維護的表結構至關重要。以下是SelectDB重要表屬性的快速概覽。

表屬性

是否必選

屬性關鍵作用

詳情連結

資料模型

不同的資料模型適用於不同的業務情境:Unique模型支援主鍵唯一性限制式,可滿足靈活高效的資料更新需求。

Duplicate模型採用追加寫入模式,適用於詳細資料的高效能分析情境。

Aggregate模型支援資料預彙總,專註於資料彙總統計情境。

資料模型

分桶

分桶用於將資料分散到叢集中的不同節點,以充分利用分布式系統的分而治之的能力來管理和查詢海量資料。

分區

分區能夠根據指定欄位(如時間、地區等)將原始表劃分為多個子表,以便於對資料進行分區管理和查詢,同時利用分區裁剪來提升查詢速度。

索引

索引能夠快速地過濾或定位元據,從而大幅提升查詢效能。

索引

資料模型

資料模型的合理選擇,對於能否滿足資料分析情境的功能需求和效能要求具有決定性影響。不同的模型適用於不同的業務情境。此處僅對各個模型進行簡要介紹,旨在協助您快速瞭解資料模型,以便於您進行模型選擇。更多詳情,請參見專題介紹文章資料模型

基礎概念

SelectDB中,資料通過表(Table)的形式在邏輯層面進行組織和管理。每張表由行(Row)和列(Column)組成。行表示資料表中的一行資料,而列用於描述該行資料中的不同欄位。

列可以分為以下兩大類:

  • Key列:Key列是指建表語句中被關鍵字UNIQUE KEYAGGREGATE KEYDUPLICATE KEY修飾的列。

  • Value列:除Key列外,其餘列均為Value列。

模型選擇指導

SelectDB中,表的資料模型分為三種,分別為Unique模型、Duplicate模型和Aggregate模型。

重要
  • 資料模型在建表時已確定且不可修改。

  • 如果在建表時未指定資料模型,將預設採用Duplicate模型,並自動選擇前三列作為Key列。

  • Unique模型、Duplicate模型和Aggregate模型中,資料均按照Key列進行排序儲存。

模型類型

模型特點

適用情境

模型不足

Unique

每一行的Key值唯一。

Key列值相同時,多行資料的Value列會按寫入的先後順序進行覆蓋。

適用於對資料有唯一主鍵要求或高效更新要求的情境。例如電商訂單、使用者屬性資訊等資料分析情境。

  • 建立同步物化視圖只能改變列的順序,不能起到彙總的作用。

Duplicate

允許多行的Key值相同。

Key列值相同時,多行資料同時儲存在系統中。

資料的寫入和查詢效率極高,適用於保留所有未經處理資料記錄的情境。例如日誌、賬單等詳細資料分析情境。

  • 不支援對存量資料做更新操作。

Aggregate

每一行的Key值唯一。

Key列值相同時,多行資料的Value列會按照建表時指定的彙總方式進行預彙總。

類似於傳統資料倉儲的Cube模型,適用於通過預彙總提升查詢效能的彙總統計情境。例如網站流量分析、定製化報表等資料分析情境。

  • count(*)查詢的支援不友好。

  • Value列的彙總方式是固定的。

快速使用模型

Unique模型

在Unique模型中,Key列值相同時,多行資料的Value列會按寫入的先後順序進行覆蓋。Unique模型提供了兩種實現方式:讀時合并(MOR,merge-on-read)和寫時合并(MOW,merge-on-write)。

由於寫時合并技術已非常成熟且穩定,並且能夠提供優異的查詢效能,因此建議您優先採用寫時合并的實現方式。此處僅簡要介紹Unique模型的寫時合并。有關讀時合并的詳細資料,請參見讀時合并(MOR)

注意事項

建立Unique模型且為寫時合并實現方式的表時,須在建表時注意以下事項。

  • 通過UNIQUE KEY指定主鍵唯一的欄位。

  • 在PROPERTIES中添加開啟寫時合并的屬性。

    "enable_unique_key_merge_on_write" = "true"
樣本

建立orders表語句如下。其表示將orders表指定為Unique模型,同時將orders表主鍵設定為由order_id和order_time組成的聯合主鍵,並啟用寫時合并模式。

CREATE TABLE IF NOT EXISTS orders
(
    `order_id` LARGEINT NOT NULL COMMENT "訂單id",
    `order_time` DATETIME NOT NULL COMMENT "訂單時間",
    `customer_id` LARGEINT NOT NULL COMMENT "使用者id",
    `total_amount` DOUBLE COMMENT "訂單總金額",
    `status` VARCHAR(20) COMMENT "訂單狀態",
    `payment_method` VARCHAR(20) COMMENT "支付方式",
    `shipping_method` VARCHAR(20) COMMENT "運輸方式",
    `customer_city` VARCHAR(20) COMMENT "使用者所在城市",
    `customer_address` VARCHAR(500) COMMENT "使用者地址"
)
UNIQUE KEY(`order_id`, `order_time`)
PARTITION BY RANGE(`order_time`) ()
DISTRIBUTED BY HASH(`order_id`)
PROPERTIES (
    "enable_unique_key_merge_on_write" = "true",
    "dynamic_partition.enable" = "true",
    "dynamic_partition.time_unit" = "DAY",
    "dynamic_partition.start" = "-7",
    "dynamic_partition.end" = "3",
    "dynamic_partition.prefix" = "p",
    "dynamic_partition.create_history_partition" = "true",
    "dynamic_partition.buckets" = "16"
);

Duplicate模型

在Duplicate模型中,Key列值相同時,多行資料同時儲存在系統中,沒有預彙總、主鍵唯一性限制式等特點。

例如,您希望記錄並分析業務系統產生的日誌資料,且期望資料按照日誌時間、日誌類型、錯誤碼進行排序儲存,您可以選擇此模型。具體建立log表的語句如下,其表示log表模型為Duplicate模型,且資料會按照log_time、log_type和error_code進行排序。

CREATE TABLE IF NOT EXISTS log
(
    `log_time` DATETIME NOT NULL COMMENT "日誌時間",
    `log_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(`log_time`, `log_type`, `error_code`)
PARTITION BY RANGE(`log_time`) ()
DISTRIBUTED BY HASH(`log_type`)
PROPERTIES (
    "dynamic_partition.enable" = "true",
    "dynamic_partition.time_unit" = "DAY",
    "dynamic_partition.start" = "-7",
    "dynamic_partition.end" = "3",
    "dynamic_partition.prefix" = "p",
    "dynamic_partition.create_history_partition" = "true",
    "dynamic_partition.buckets" = "16"
);

Aggregate模型

注意事項

在Aggregate模型中,Key列值相同時,多行資料的Value列會按照建表時指定的彙總方式進行預彙總。因此,在建立Aggregate模型的表時,需特別關注以下事項。

  • 通過AGGREGATE KEY指定Key列,相同Key列的資料行將進行彙總。

  • 指定Value的彙總方式。目前支援的彙總方式如下:

    彙總方式參數

    參數說明

    SUM

    求和。適用數實值型別。

    MIN

    求最小值。適合數實值型別。

    MAX

    求最大值。適合數實值型別。

    REPLACE

    替換。對於維度列相同的行,指標列會按照匯入的先後順序,後匯入的替換先匯入的。

    REPLACE_IF_NOT_NULL

    非空值替換。和REPLACE的區別在於對於null值,不做替換。這裡要注意的是欄位預設值要給NULL,而不能是Null 字元串,如果是Null 字元串,會給你替換成Null 字元串。

    HLL_UNION

    HLL類型的列的彙總方式,通過HyperLogLog演算法彙總。

    BITMAP_UNION

    BITMAP類型的列的彙總方式,進行位元影像的並集彙總。

樣本

例如,您需要對使用者行為進行統計分析,記錄其最後訪問時間、總消費額、最大停留時間和最短停留時間,您可以選擇此模型。具體建立user_behavior表的語句如下。其表示當多條資料的Key列(使用者ID、資料寫入日期、使用者所在城市、使用者年齡和使用者性別)相同時,使用者的Value列進行預彙總。彙總規則如下:

  • 使用者最後一次訪問時間:取多條使用者行為資料中last_visit_date欄位的最大值。

  • 使用者總消費:多條資料中使用者消費的總和。

  • 使用者最大停留時間:取多條使用者行為資料中max_dwell_time欄位的最大值

  • 使用者最小停留時間:取多條使用者行為資料中min_dwell_time欄位的最小值

CREATE TABLE IF NOT EXISTS user_behavior
(
    `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 "使用者最後一次訪問時間",
    `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`)
PARTITION BY RANGE(`date`) ()
DISTRIBUTED BY HASH(`user_id`)
PROPERTIES (
    "dynamic_partition.enable" = "true",
    "dynamic_partition.time_unit" = "DAY",
    "dynamic_partition.start" = "-7",
    "dynamic_partition.end" = "3",
    "dynamic_partition.prefix" = "p",
    "dynamic_partition.create_history_partition" = "true",
    "dynamic_partition.buckets" = "16"
);

資料劃分概述

SelectDB支援兩層資料劃分,如下圖所示。第一層是分區(Partition),用於對資料進行邏輯劃分,分區是使用者進行資料管理的最小單元。第二層是分桶(Tablet),用於對資料進行物理劃分,分桶是系統進行資料打散、移動等操作的最小單元。

image

分區與分桶的關聯
  • 一個分桶僅屬於一個分區,而一個分區則包含多個分桶。

  • 在建表過程中,如果採用了分區(Partition),則表先按分區規則進行劃分,分區內再按指定的分桶規則進行劃分;如果未使用分區,則表直接按指定的分桶規則進行劃分。

  • 在資料寫入過程中,資料首先被劃分至相應的分區,隨後在分區內依據分桶規則進一步寫入至不同的分桶中。分桶是對分區資料的進一步細分,其目的是為了更加均勻地分布資料,從而提升查詢效率。

分區(Partition)

SelectDB的儲存引擎中,分區是一種資料群組織方式,用於將表中的資料按照使用者定義的規則劃分為多個獨立的部分,從而實現資料的邏輯劃分。這有助於提升查詢效率,同時也使得資料管理更加靈活和便捷。此處僅對分區進行簡要介紹,旨在協助您快速瞭解分區,以便於您進行分區選型。更多詳情,請參見分區動態分區

分區選擇指導

SelectDB支援兩種分區方式:Range分區和List分區。同時,也提供了簡單易用的動態資料分割函數,以實現對分區的自動化管理。不同的分區方式,適用於不同的業務情境。

分區方式

支援的列類型

指定分區資訊方式

適用情境

Range

列類型:DATE、DATETIME、TINYINT、SMALLINT、INT、BIGINT、LARGEINT

支援四種寫法:

  1. VALUES [...):定義分區的左閉右開區間。

  2. VALUES LESS THAN (...):僅定義分區上界。下界由上一個分區的上界決定。

  3. BATCH RANGE:大量建立數字類型和時間類型的Range分區,定義分區的左閉右開區間,設定步長。

  4. MULTI RANGE:大量建立Range分區,定義分區的左閉右開區間。

適用於對資料劃分區間進行管理,典型的情境是按時間進行分區。

List

列類型:BOOLEAN、TINYINT、SMALLINT、INT、BIGINT、LARGEINT、DATE、DATETIME、CHAR、VARCHAR

支援通過VALUES IN (...)來指定每個分區包含的枚舉值。

適用於依據資料的既有類別或固定特性進行資料管理,分區列通常為枚舉值,例如根據使用者所屬地區進行資料劃分管理。

注意事項

  • SelectDB的表可分為分區表和無分區表。該屬性可選,在建表時確定是否進行分區,之後不可更改。具體而言,對於分區表,您可以在後續使用過程中對分區進行增刪操作;而對於無分區表,則無法再進行增加分區等操作。

  • 分區列必須為Key列,可指定一列或多列。

  • 不論分區列是什麼類型,在寫分區值時,都需要加雙引號。

  • 分區的數量在理論上並沒有上限。

  • 在建立分區時,必須確保每個分區的取值範圍不重疊。

快速使用分區

Range分區

Range分區是指按照分區欄位範圍,對資料進行劃分管理,是最常用的分區方式。典型的使用情境是按照時間進行資料分區,方便對海量的時間序資料進行管理、查詢最佳化等。

分區分桶的最終目的是合理地劃分資料,分區規則設定合理性的主要標準是:

  • 在分區及分桶規則下,每個分桶(Tablet)的資料量在1~10 GB的範圍內;

  • 根據您管理資料的粒度確定分區粒度(例如,在日誌情境下,您通常需要按天淘汰歷史資料,此時選擇以天為分區粒度比較合適)。

在日誌情境下,經常按照時間範圍過濾查詢資料,且需要按照時間淘汰歷史分區,您可以將log_time欄位指定為分區列,並採取按天分區的方式,樣本如下。

CREATE TABLE IF NOT EXISTS log
(
 `log_time` DATETIME NOT NULL COMMENT "日誌時間",
 `log_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(`log_time`, `log_type`, `error_code`)
PARTITION BY RANGE(`log_time`)
(
 PARTITION `p20240201` VALUES [("2024-02-01"), ("2024-02-02")),
 PARTITION `p20240202` VALUES [("2024-02-02"), ("2024-02-03")),
 PARTITION `p20240203` VALUES [("2024-02-03"), ("2024-02-04"))
)
DISTRIBUTED BY HASH(`log_type`);

建表完成後,您可以通過如下SQL查看錶的分區資訊。

SHOW partitions FROM log;
p20240201: [("2024-02-01"), ("2024-02-02"))
p20240202: [("2024-02-02"), ("2024-02-03"))
p20240203: [("2024-02-03"), ("2024-02-04"))

當您使用以下語句查詢資料時,就會命中分區p20240202: [("2024-02-02"), ("2024-02-03")),系統不會掃描剩餘兩個分區的資料,從而提高了查詢資料的速度。

SELECT * FROM orders WHERE order_time = '2024-02-02';

List分區

List分區是按照分區欄位的枚舉值,對資料進行劃分管理。當對採用List分區的表進行查詢時,可結合過濾條件快速進行分區裁剪,提升查詢效能。

您可以根據操作業務資料時常用的欄位來選擇List分區列。需要注意的是,各個分區之間的資料量要均勻,避免嚴重的資料扭曲。

例如,在電商情境中,訂單資料量通常非常龐大,且某些情境經常需要根據訂單使用者所屬城市來查詢分析此類資料。因此,為了更方便地管理和查詢資料,可以將customer_city欄位指定為分區列。假如資料量按地區的分布如下:

  • 北京、上海和中國香港預計有6GB。

  • 紐約、舊金山預計有5GB。

  • 東京預計有5GB。

此時您可以按照以下樣本進行分區。

CREATE TABLE IF NOT EXISTS orders
(
    `order_id` LARGEINT NOT NULL COMMENT "訂單id",
    `order_time` DATETIME NOT NULL COMMENT "訂單時間",
    `customer_city` VARCHAR(20) COMMENT "使用者所在城市",
    `customer_id` LARGEINT NOT NULL COMMENT "使用者id",
    `total_amount` DOUBLE COMMENT "訂單總金額",
    `status` VARCHAR(20) COMMENT "訂單狀態",
    `payment_method` VARCHAR(20) COMMENT "支付方式",
    `shipping_method` VARCHAR(20) COMMENT "運輸方式",
    `customer_address` VARCHAR(500) COMMENT "使用者地址"
)
UNIQUE KEY(`order_id`, `order_time`, `customer_city`)
PARTITION BY LIST(`customer_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(`order_id`) BUCKETS 16
PROPERTIES (
    "enable_unique_key_merge_on_write" = "true"
);

建表完成後,您可以通過如下SQL查看錶的分區資訊,該表會自動產生以下3個分區。

SHOW partitions FROM orders;
p_cn: ("Beijing", "Shanghai", "Hong Kong")
p_usa: ("New York", "San Francisco")
p_jp: ("Tokyo")

當您使用以下語句查詢資料時,就會命中分區p_jp: ("Tokyo"),系統不會掃描剩餘兩個分區的資料,從而提高了查詢資料的速度。

SELECT * FROM orders WHERE customer_city = 'Tokyo';

使用動態分區

實際生產環境中,資料表的分區數量可能比較多,此時手動管理分區的工作將變得十分繁瑣,這為資料庫管理員帶來了額外的維護成本。SelectDB允許在建表時設定動態分區規則以進行自動化分區管理。

例如,在電商中,針對訂單資訊表,經常按照時間範圍過濾查詢資料,且需要對歷史訂單進行轉儲歸檔的情境。您可以將order_time欄位指定為分區列,並在PROPERTIES中設定動態分區屬性。比如在PROPERTIES中設定該分區採取按天分區(dynamic_partition.time_unit)的方式,只保留最近180天(dynamic_partition.start)的分區,並且預先建立未來3天(dynamic_partition.end)的分區,樣本如下。

重要

下述語句中PARTITION BY RANGE(`order_time`) ()末尾的()並非語法錯誤,如果您要使用動態分區,此括弧為固定文法,必不可少。

CREATE TABLE IF NOT EXISTS orders
(
    `order_id` LARGEINT NOT NULL COMMENT "訂單id",
    `order_time` DATETIME NOT NULL COMMENT "訂單時間",
    `customer_id` LARGEINT NOT NULL COMMENT "使用者id",
    `total_amount` DOUBLE COMMENT "訂單總金額",
    `status` VARCHAR(20) COMMENT "訂單狀態",
    `payment_method` VARCHAR(20) COMMENT "支付方式",
    `shipping_method` VARCHAR(20) COMMENT "運輸方式",
    `customer_city` VARCHAR(20) COMMENT "使用者所在城市",
    `customer_address` VARCHAR(500) COMMENT "使用者地址"
)
UNIQUE KEY(`order_id`, `order_time`)
PARTITION BY RANGE(`order_time`) ()
DISTRIBUTED BY HASH(`order_id`)
PROPERTIES (
    "enable_unique_key_merge_on_write" = "true",
    "dynamic_partition.enable" = "true",
    "dynamic_partition.time_unit" = "DAY",
    "dynamic_partition.start" = "-180",
    "dynamic_partition.end" = "3",
    "dynamic_partition.prefix" = "p",
    "dynamic_partition.create_history_partition" = "true",
    "dynamic_partition.buckets" = "16"
);

當您預計表的分區數量較多時,強烈建議您學習動態分區的相關內容,詳情請參見動態分區

分桶(Tablet

SelectDB的儲存引擎中,資料根據指定列的Hash值劃分到不同的分桶(Tablet),分桶則由叢集中的不同節點進行管理,從而利用分布式系統的能力來進行管理、查詢海量資料。在建表時,通過DISTRIBUTED BY HASH(`<分桶列>`) BUCKETS <分桶數量>進行分桶的設定。有關分桶的詳細資料,請參見分桶

注意事項

  • 如果建表時使用了分區(Partition),則DISTRIBUTED...語句所描述的是資料在各個分區內的劃分規則;如果未使用分區,則所描述的是對整個表的資料劃分規則。

  • 分桶列可以包含多個。

    對於Aggregate和Unique模型,分桶列必須為Key列;而對於Duplicate模型,分桶列則沒有限制。

    分桶列建議選擇唯一值多的高基數列,以便打散資料,避免資料扭曲。

  • 分桶(Tablet)的數量理論上沒有上限。

    單個分桶(Tablet)的資料量理論上沒有上下界,但建議在1~10 GB的範圍內。

    如果單個分桶(Tablet)資料量過小,容易導致分桶過多,中繼資料管理壓力增大。

    如果單個分桶(Tablet)資料量過大,不利於副本的遷移、分布式叢集的充分利用,增加Schema變更或者索引建立等操作失敗重試的代價(這些操作失敗重試的粒度是Tablet)。

分桶列選擇指導

在表設計過程中,分桶列的選擇對查詢的效能和並發量有著重要影響,分桶列選擇的原則如下所示。當業務中存在多種查詢需求時,會產生多種分桶列的期望,此時應優先根據最主要查詢的需求進行選擇。

選擇原則

作用

優先保障資料均勻打散,選擇高基數列或多列組合。

資料在叢集節點上分布更均衡。對於過濾效果不佳、進行大量資料掃描的查詢,可充分利用分布式系統的資源提升查詢效能。

選擇經常用於查詢過濾條件的列,兼顧資料裁剪加速查詢。

相同分桶列的資料聚集在一起。對於指定分桶列作為過濾條件的點查詢,可快速進行資料裁剪提高查詢並發。

說明

點查詢通常用於從資料庫中檢索特定條件下的少量資料。這種查詢通過指定特定的條件(例如通過主鍵、高基數列進行過濾),來精確確定位並擷取資料庫中合格少量資料。

使用樣本

在電商情境中,大量查詢按照訂單維度進行過濾查詢,也有部分查詢對全量訂單資料進行統計分析。此時,您可以選擇訂單資訊表Key列中的高基數列order_id作為分桶列,可保障資料能夠均勻地分配到每個桶,且單個order_id的資料聚集在一起,可同時滿足前述兩種類型查詢的效能需求。具體建表語句如下。

CREATE TABLE IF NOT EXISTS orders
(
    `order_id` LARGEINT NOT NULL COMMENT "訂單id",
    `order_time` DATETIME NOT NULL COMMENT "訂單時間",
    `customer_id` LARGEINT NOT NULL COMMENT "使用者id",
    `total_amount` DOUBLE COMMENT "訂單總金額",
    `status` VARCHAR(20) COMMENT "訂單狀態",
    `payment_method` VARCHAR(20) COMMENT "支付方式",
    `shipping_method` VARCHAR(20) COMMENT "運輸方式",
    `customer_city` VARCHAR(20) COMMENT "使用者所在城市",
    `customer_address` VARCHAR(500) COMMENT "使用者地址"
)
UNIQUE KEY(`order_id`, `order_time`)
PARTITION BY RANGE(`order_time`) ()
DISTRIBUTED BY HASH(`order_id`)
PROPERTIES (
    "enable_unique_key_merge_on_write" = "true",
    "dynamic_partition.enable" = "true",
    "dynamic_partition.time_unit" = "DAY",
    "dynamic_partition.start" = "-7",
    "dynamic_partition.end" = "3",
    "dynamic_partition.prefix" = "p",
    "dynamic_partition.create_history_partition" = "true",
    "dynamic_partition.buckets" = "16"
);

索引

索引在資料庫設計中至關重要,合適的索引可大幅提高查詢效能。建立索引存在一定的成本,可能導致額外的儲存空間佔用以及寫入效能的下降。此處僅對常用索引進行簡要介紹,以協助您快速瞭解索引,以便於您進行索引選型。更多詳情,請參見索引加速

設計指南

  • 最常使用的過濾條件應指定為Key自動建立首碼索引,因為其過濾效果最佳。然而,一個表只能擁有一個首碼索引,因此建議將其應用於最頻繁的過濾條件上。

  • 對於其他過濾加速需求,首選建立倒排索引,因其適用範圍廣泛,支援多條件組合。對於字串的等值、LIKE匹配查詢情境,可考慮輕量級的BloomFilter、NGram BloomFilter索引。

索引選擇指導

SelectDB中,表的索引的構建方式有內建和自訂兩種。對於內建索引,系統會自動建立。而對於自訂索引,需要您在建表時或者建表後,根據需要自行建立。

構建方式

索引類型

支援的查詢類型

不支援的查詢類型

優勢

劣勢

內建

首碼索引

  • 等於、不等於查詢

  • 範圍查詢

  • LIKE查詢

  • MATCH(關鍵詞、短語)

首碼索引佔用的空間相對較小,能夠在記憶體中進行全量緩衝,從而實現快速定位元據塊,顯著提升查詢效率。

一個表只能有一個首碼索引。

自訂

倒排索引(推薦)

  • 字串、數值、日期時間類型的等於、不等於查詢、範圍查詢

  • 字串類型MATCH(關鍵詞、短語)

  • 文本類型的全文檢索索引

支援的查詢類型豐富。支援在建表時、建表後按需建立索引,並支援索引刪除。

索引儲存空間相對較大。

BloomFilter索引

等於查詢

  • 不等於查詢

  • 範圍查詢

  • LIKE查詢

  • MATCH(關鍵詞、短語)

索引構建佔用的計算和儲存資源少。

支援的查詢類型少,只支援等於查詢。

NGram BloomFilter索引

LIKE查詢

  • 等於、不等於查詢

  • 範圍查詢

  • MATCH(關鍵詞、短語)

提高LIKE查詢速度,索引構建佔用的計算和儲存資源少。

只支援LIKE加速。

快速使用索引

倒排索引

SelectDB支援倒排索引,可用於滿足文字欄位的全文檢索索引、以及普通欄位的等值或範圍查詢,能夠快速從大量資料中篩選出滿足條件的資料。此處僅簡紹如何建立倒排索引,更多資訊,請參見倒排索引

建表時建立索引

在電商情境中,根據使用者ID、使用者地址關鍵詞查詢訂單資訊是高頻操作,此時可以在customer_idcustomer_address欄位上建立倒排索引來提高查詢速度。具體建表語句如下。

CREATE TABLE IF NOT EXISTS orders
(
    `order_id` LARGEINT NOT NULL COMMENT "訂單id",
    `order_time` DATETIME NOT NULL COMMENT "訂單時間",
    `customer_id` LARGEINT NOT NULL COMMENT "使用者id",
    `total_amount` DOUBLE COMMENT "訂單總金額",
    `status` VARCHAR(20) COMMENT "訂單狀態",
    `payment_method` VARCHAR(20) COMMENT "支付方式",
    `shipping_method` VARCHAR(20) COMMENT "運輸方式",
    `customer_city` VARCHAR(20) COMMENT "使用者所在城市",
    `customer_address` VARCHAR(500) COMMENT "使用者地址",
    INDEX idx_customer_id (`customer_id`) USING INVERTED,
    INDEX idx_customer_address (`customer_address`) USING INVERTED PROPERTIES("parser" = "chinese")
)
UNIQUE KEY(`order_id`, `order_time`)
PARTITION BY RANGE(`order_time`) ()
DISTRIBUTED BY HASH(`order_id`)
PROPERTIES (
    "enable_unique_key_merge_on_write" = "true",
    "dynamic_partition.enable" = "true",
    "dynamic_partition.time_unit" = "DAY",
    "dynamic_partition.start" = "-7",
    "dynamic_partition.end" = "3",
    "dynamic_partition.prefix" = "p",
    "dynamic_partition.create_history_partition" = "true",
    "dynamic_partition.buckets" = "16"
);
已有表建立索引

在電商情境中,根據使用者ID查詢訂單資訊資料是一個高頻操作,但如果建表時沒有為customer_id欄位建立倒排索引,可以使用以下語句為其增加索引。

ALTER TABLE orders ADD INDEX idx_customer_id (`customer_id`) USING INVERTED;

首碼索引

首碼索引是在底層資料按照Key列排序的基礎上,選擇首碼的一個或多個Key列構建的索引,其本質是基於資料排序特性進行二分尋找。首碼索引屬於內建索引,建表後SelectDB自動建立。

首碼索引沒有專門的文法去定義,系統會根據建表的Key欄欄位定義順序,選取前36個位元組所能覆蓋的欄位作為首碼索引,但當遇到VARCHAR類型時,首碼索引會直接截斷,後面的Key列不再加入首碼索引。

建表時欄位定義的順序尤為重要,它決定了哪些欄位會被用作首碼索引,強烈建議您參考如下原則確定Key列順序:

  • 高頻用於過濾條件的、高基數的Key列放在其他欄位之前。如Duplicate模型章節的日誌情境中,日誌時間log_time放在錯誤碼error_code之前。

  • 等值過濾條件的Key列放在區間過濾條件的Key列之前。如倒排索引章節的電商情境中,時間order_time通常按照區間過濾,放在訂單號order_id之後。

  • 普通類型欄位放在VARCHAR類型欄位之前。如INT類型的Key列放在VARCHAR類的KEY列之前。

使用樣本

倒排索引章節的電商情境,訂單資訊表的首碼索引為order_id+order_time,當查詢條件是首碼索引的首碼時(即查詢條件包含order_id或同時包含order_id和order_time),可以極大的加快查詢速度。如以下兩個樣本,樣本一的查詢速度會遠高於樣本二的查詢速度。

樣本一

SELECT * FROM orders WHERE order_id = 1829239 and order_time = '2024-02-01';

樣本二

SELECT * FROM orders WHERE order_time = '2024-02-01';

下一步

完成本教程的前三個步驟後,您已初步瞭解SelectDB,並具備設計符合業務需求的資料庫表的基本能力。下一步,您可以根據後續指引,瞭解您業務涉及的具體功能,例如資料移轉、查詢外部資料源、版本升級等。更多功能,請參見後續指引