良好的表結構設計不僅能支援豐富的功能需求,還能大幅提升資料庫系統的效能、可維護性和可擴充性等,因此資料庫的表結構設計至關重要。本文為您介紹在ApsaraDB for SelectDB中,設計表結構時需要重點關注的表屬性,並協助您快速掌握如何根據業務情境選擇合適的表設計,從而更好的滿足業務需求。
重要表屬性概覽
在業務接入SelectDB時,根據業務情境做好重要表屬性的設計,對於構建出能滿足業務需求且高效能、易維護的表結構至關重要。以下是SelectDB重要表屬性的快速概覽。
表屬性 | 是否必選 | 屬性關鍵作用 | 詳情連結 |
資料模型 | 是 | 不同的資料模型適用於不同的業務情境:Unique模型支援主鍵唯一性限制式,可滿足靈活高效的資料更新需求。 Duplicate模型採用追加寫入模式,適用於詳細資料的高效能分析情境。 Aggregate模型支援資料預彙總,專註於資料彙總統計情境。 | |
分桶 | 是 | 分桶用於將資料分散到叢集中的不同節點,以充分利用分布式系統的分而治之的能力來管理和查詢海量資料。 | |
分區 | 否 | 分區能夠根據指定欄位(如時間、地區等)將原始表劃分為多個子表,以便於對資料進行分區管理和查詢,同時利用分區裁剪來提升查詢速度。 | |
索引 | 否 | 索引能夠快速地過濾或定位元據,從而大幅提升查詢效能。 |
資料模型
資料模型的合理選擇,對於能否滿足資料分析情境的功能需求和效能要求具有決定性影響。不同的模型適用於不同的業務情境。此處僅對各個模型進行簡要介紹,旨在協助您快速瞭解資料模型,以便於您進行模型選擇。更多詳情,請參見專題介紹文章資料模型。
基礎概念
在SelectDB中,資料通過表(Table)的形式在邏輯層面進行組織和管理。每張表由行(Row)和列(Column)組成。行表示資料表中的一行資料,而列用於描述該行資料中的不同欄位。
列可以分為以下兩大類:
Key列:Key列是指建表語句中被關鍵字
UNIQUE KEY、AGGREGATE KEY或DUPLICATE 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模型,適用於通過預彙總提升查詢效能的彙總統計情境。例如網站流量分析、定製化報表等資料分析情境。 |
|
快速使用模型
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),用於對資料進行物理劃分,分桶是系統進行資料打散、移動等操作的最小單元。
分區與分桶的關聯
一個分桶僅屬於一個分區,而一個分區則包含多個分桶。
在建表過程中,如果採用了分區(Partition),則表先按分區規則進行劃分,分區內再按指定的分桶規則進行劃分;如果未使用分區,則表直接按指定的分桶規則進行劃分。
在資料寫入過程中,資料首先被劃分至相應的分區,隨後在分區內依據分桶規則進一步寫入至不同的分桶中。分桶是對分區資料的進一步細分,其目的是為了更加均勻地分布資料,從而提升查詢效率。
分區(Partition)
在SelectDB的儲存引擎中,分區是一種資料群組織方式,用於將表中的資料按照使用者定義的規則劃分為多個獨立的部分,從而實現資料的邏輯劃分。這有助於提升查詢效率,同時也使得資料管理更加靈活和便捷。此處僅對分區進行簡要介紹,旨在協助您快速瞭解分區,以便於您進行分區選型。更多詳情,請參見分區和動態分區。
分區選擇指導
SelectDB支援兩種分區方式:Range分區和List分區。同時,也提供了簡單易用的動態資料分割函數,以實現對分區的自動化管理。不同的分區方式,適用於不同的業務情境。
分區方式 | 支援的列類型 | 指定分區資訊方式 | 適用情境 |
Range | 列類型:DATE、DATETIME、TINYINT、SMALLINT、INT、BIGINT、LARGEINT | 支援四種寫法:
| 適用於對資料劃分區間進行管理,典型的情境是按時間進行分區。 |
List | 列類型:BOOLEAN、TINYINT、SMALLINT、INT、BIGINT、LARGEINT、DATE、DATETIME、CHAR、VARCHAR | 支援通過 | 適用於依據資料的既有類別或固定特性進行資料管理,分區列通常為枚舉值,例如根據使用者所屬地區進行資料劃分管理。 |
注意事項
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中,表的索引的構建方式有內建和自訂兩種。對於內建索引,系統會自動建立。而對於自訂索引,需要您在建表時或者建表後,根據需要自行建立。
構建方式 | 索引類型 | 支援的查詢類型 | 不支援的查詢類型 | 優勢 | 劣勢 |
內建 | 首碼索引 |
|
| 首碼索引佔用的空間相對較小,能夠在記憶體中進行全量緩衝,從而實現快速定位元據塊,顯著提升查詢效率。 | 一個表只能有一個首碼索引。 |
自訂 | 倒排索引(推薦) |
| 無 | 支援的查詢類型豐富。支援在建表時、建表後按需建立索引,並支援索引刪除。 | 索引儲存空間相對較大。 |
BloomFilter索引 | 等於查詢 |
| 索引構建佔用的計算和儲存資源少。 | 支援的查詢類型少,只支援等於查詢。 | |
NGram BloomFilter索引 | LIKE查詢 |
| 提高LIKE查詢速度,索引構建佔用的計算和儲存資源少。 | 只支援LIKE加速。 |
快速使用索引
倒排索引
SelectDB支援倒排索引,可用於滿足文字欄位的全文檢索索引、以及普通欄位的等值或範圍查詢,能夠快速從大量資料中篩選出滿足條件的資料。此處僅簡紹如何建立倒排索引,更多資訊,請參見倒排索引。
建表時建立索引
在電商情境中,根據使用者ID、使用者地址關鍵詞查詢訂單資訊是高頻操作,此時可以在customer_id和customer_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,並具備設計符合業務需求的資料庫表的基本能力。下一步,您可以根據後續指引,瞭解您業務涉及的具體功能,例如資料移轉、查詢外部資料源、版本升級等。更多功能,請參見後續指引。