成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

TiDB 源碼閱讀系列文章(二十)Table Partition

K_B_Z / 1703人閱讀

摘要:部分主要流程如下把上文提到語法解析階段會把語句中相關信息轉換成然后負責把結構轉換即的元信息。最后把的元信息追加到的元信息中,具體實現(xiàn)在這里。會把要刪除的分區(qū)從元信息刪除掉,刪除前會做的檢查。

作者:肖亮亮

Table Partition 什么是 Table Partition

Table Partition 是指根據(jù)一定規(guī)則,將數(shù)據(jù)庫中的一張表分解成多個更小的容易管理的部分。從邏輯上看只有一張表,但是底層卻是由多個物理分區(qū)組成。相信對有關系型數(shù)據(jù)庫使用背景的用戶來說可能并不陌生。

TiDB 正在支持分區(qū)表這一特性。在 TiDB 中分區(qū)表是一個獨立的邏輯表,但是底層由多個物理子表組成。物理子表其實就是普通的表,數(shù)據(jù)按照一定的規(guī)則劃分到不同的物理子表類內。程序讀寫的時候操作的還是邏輯表名字,TiDB 服務器自動去操作分區(qū)的數(shù)據(jù)。

分區(qū)表有什么好處?

優(yōu)化器可以使用分區(qū)信息做分區(qū)裁剪。在語句中包含分區(qū)條件時,可以只掃描一個或多個分區(qū)表來提高查詢效率。

方便地進行數(shù)據(jù)生命周期管理。通過創(chuàng)建、刪除分區(qū)、將過期的數(shù)據(jù)進行 高效的歸檔,比使用 Delete 語句刪除數(shù)據(jù)更加優(yōu)雅,打散寫入熱點,將一個表的寫入分散到多個物理表,使得負載分散開,對于存在 Sequence 類型數(shù)據(jù)的表來說(比如 Auto Increament ID 或者是 create time 這類的索引)可以顯著地提升寫入吞吐。

分區(qū)表的限制

TiDB 默認一個表最多只能有 1024 個分區(qū) ,默認是不區(qū)分表名大小寫的。

Range, List, Hash 分區(qū)要求分區(qū)鍵必須是 INT 類型,或者通過表達式返回 INT 類型。但 Key 分區(qū)的時候,可以使用其他類型的列(BLOB,TEXT 類型除外)作為分區(qū)鍵。

如果分區(qū)字段中有主鍵或者唯一索引的列,那么有主鍵列和唯一索引的列都必須包含進來。即:分區(qū)字段要么不包含主鍵或者索引列,要么包含全部主鍵和索引列。

TiDB 的分區(qū)適用于一個表的所有數(shù)據(jù)和索引。不能只對表數(shù)據(jù)分區(qū)而不對索引分區(qū),也不能只對索引分區(qū)而不對表數(shù)據(jù)分區(qū),也不能只對表的一部分數(shù)據(jù)分區(qū)。

常見分區(qū)表的類型

Range 分區(qū):按照分區(qū)表達式的范圍來劃分分區(qū)。通常用于對分區(qū)鍵需要按照范圍的查詢,分區(qū)表達式可以為列名或者表達式 ,下面的 employees 表當中 p0, p1, p2, p3 表示 Range 的訪問分別是 ?(min, 1991), [1991, 1996), [1996, 2001), [2001, max) 這樣一個范圍。

CREATE  TABLE employees (
id INT  NOT  NULL,
fname VARCHAR(30),
separated DATE  NOT  NULL
)

PARTITION BY RANGE ( YEAR(separated) ) (
PARTITION p0 VALUES LESS THAN (1991),
PARTITION p1 VALUES LESS THAN (1996),
PARTITION p2 VALUES LESS THAN (2001),
PARTITION p3 VALUES LESS THAN MAXVALUE
);

List 分區(qū):按照 List 中的值分區(qū),主要用于枚舉類型,與 Range 分區(qū)的區(qū)別在于 Range 分區(qū)的區(qū)間范圍值是連續(xù)的。

Hash 分區(qū):Hash 分區(qū)需要指定分區(qū)鍵和分區(qū)個數(shù)。通過 Hash 的分區(qū)表達式計算得到一個 INT 類型的結果,這個結果再跟分區(qū)個數(shù)取模得到具體這行數(shù)據(jù)屬于那個分區(qū)。通常用于給定分區(qū)鍵的點查詢,Hash 分區(qū)主要用來分散熱點讀,確保數(shù)據(jù)在預先確定個數(shù)的分區(qū)中盡可能平均分布。

Key 分區(qū):類似 Hash 分區(qū),Hash 分區(qū)允許使用用戶自定義的表達式,但 Key 分區(qū)不允許使用用戶自定義的表達式。Hash 僅支持整數(shù)分區(qū),而 Key 分區(qū)支持除了 Blob 和 Text 的其他類型的列作為分區(qū)鍵。

TiDB Table Partition 的實現(xiàn)

本文接下來按照?TiDB 源碼的 release-2.1 分支講解,部分講解會在 source-code 分支代碼,目前只支持 Range 分區(qū)所以這里只介紹 Range 類型分區(qū) Table Partition 的源碼實現(xiàn),包括 create table、select 、add partition、insert 、drop partition 這五種語句。

create table

create table 會重點講構建 Partition 的這部分,更詳細的可以看 TiDB 源碼閱讀系列文章(十七)DDL 源碼解析,當用戶執(zhí)行創(chuàng)建分區(qū)表的SQL語句,語法解析(Parser)階段會把 SQL 語句中 Partition 相關信息轉換成 ast.PartitionOptions,下文會介紹。接下來會做一系列 Check,分區(qū)名在當前的分區(qū)表中是否唯一、是否分區(qū) Range 的值保持遞增、如果分區(qū)鍵構成為表達式檢查表達式里面是否是允許的函數(shù)、檢查分區(qū)鍵必須是 INT 類型,或者通過表達式返回 INT 類型、檢查分區(qū)鍵是否符合一些約束。

解釋下分區(qū)鍵,在分區(qū)表中用于計算這一行數(shù)據(jù)屬于哪一個分區(qū)的列的集合叫做分區(qū)鍵。分區(qū)鍵構成可能是一個字段或多個字段也可以是表達式。

// PartitionOptions specifies the partition options.
type PartitionOptions struct {
Tp          model.PartitionType
Expr        ExprNode
ColumnNames []*ColumnName
Definitions []*PartitionDefinition
}
    ?
// PartitionDefinition defines a single partition.
type PartitionDefinition struct {
Name     model.CIStr
LessThan []ExprNode
MaxValue bool
Comment  string
}
    

PartitionOptions 結構中 Tp 字段表示分區(qū)類型,Expr 字段表示分區(qū)鍵,ColumnNames 字段表示 Columns 分區(qū),這種類型分區(qū)有分為 Range columns 分區(qū)和 List columns 分區(qū),這種分區(qū)目前先不展開介紹。PartitionDefinition 其中 Name 字段表示分區(qū)名,LessThan 表示分區(qū) Range 值,MaxValue 字段表示 Range 值是否為最大值,Comment 字段表示分區(qū)的描述。

CreateTable Partition 部分主要流程如下:

把上文提到語法解析階段會把 SQL語句中 Partition 相關信息轉換成 ast.PartitionOptions , 然后 buildTablePartitionInfo 負責把 PartitionOptions 結構轉換 PartitionInfo, ?即 Partition 的元信息。

checkPartitionNameUnique 檢查分區(qū)名是否重復,分表名是不區(qū)大小寫的。

對于每一分區(qū) Range 值進行 Check,checkAddPartitionValue 就是檢查新增的 Partition 的 Range 需要比之前所有 Partition 的 Range 都更大。

TiDB 單表最多只能有 1024 個分區(qū) ,超過最大分區(qū)的限制不會創(chuàng)建成功。

如果分區(qū)鍵構成是一個包含函數(shù)的表達式需要檢查表達式里面是否是允許的函數(shù) checkPartitionFuncValid。

檢查分區(qū)鍵必須是 INT 類型,或者通過表達式返回 INT 類型,同時檢查分區(qū)鍵中的字段在表中是否存在 checkPartitionFuncType。

如果分區(qū)字段中有主鍵或者唯一索引的列,那么多有主鍵列和唯一索引列都必須包含進來。即:分區(qū)字段要么不包含主鍵或者索引列,要么包含全部主鍵和索引列 checkRangePartitioningKeysConstraints。

通過以上對 PartitionInfo 的一系列 check 主要流程就講完了,需要注意的是我們沒有對 PartitionInfo 的元數(shù)據(jù)持久化多帶帶存儲而是附加在 TableInfo Partition 中。

add partition

add partition 首先需要從 SQL 中解析出來 Partition 的元信息,然后對當前添加的分區(qū)會有一些 Check 和限制,主要檢查是否是分區(qū)表、分區(qū)名是已存在、最大分區(qū)數(shù)限制、是否 Range 值保持遞增,最后把 Partition 的元信息 PartitionInfo 追加到 Table 的元信息 TableInfo中,具體如下:

檢查是否是分區(qū)表,若不是分區(qū)表則報錯提示。

用戶的 SQL 語句被解析成將 ast.PartitionDefinition 然后 buildPartitionInfo 做的事就是保存表原來已存在的分區(qū)信息例如分區(qū)類型,分區(qū)鍵,分區(qū)具體信息,每個新分區(qū)分配一個獨立的 PartitionID。

TiDB 默認一個表最多只能有 1024 個分區(qū),超過最大分區(qū)的限制會報錯。

對于每新增一個分區(qū)需要檢查 Range 值進行 Check,checkAddPartitionValue 簡單說就是檢查新增的 Partition 的 Range 需要比之前所有 Partition 的 Rrange 都更大。

checkPartitionNameUnique 檢查分區(qū)名是否重復,分表名是不區(qū)大小寫的。

最后把 Partition 的元信息 PartitionInfo 追加到 Table 的元信息 TableInfo.Partition 中,具體實現(xiàn)在這里 updatePartitionInfo。

drop partition

drop partition 和 drop table 類似,只不過需要先找到對應的 Partition ID,然后刪除對應的數(shù)據(jù),以及修改對應 Table 的 Partition 元信息,兩者區(qū)別是如果是 drop table 則刪除整個表數(shù)據(jù)和表的 TableInfo 元信息,如果是 drop partition 則需刪除對應分區(qū)數(shù)據(jù)和 TableInfo 中的 Partition 元信息,刪除分區(qū)之前會有一些 Check 具體如下:

只能對分區(qū)表做 drop partition 操作,若不是分區(qū)表則報錯提示。

checkDropTablePartition 檢查刪除的分區(qū)是否存在,TiDB 默認是不能刪除所有分區(qū),如果想刪除最后一個分區(qū),要用 drop table 代替。

removePartitionInfo 會把要刪除的分區(qū)從 Partition 元信息刪除掉,刪除前會做checkDropTablePartition 的檢查。

對分區(qū)表數(shù)據(jù)則需要拿到 PartitionID 根據(jù)插入數(shù)據(jù)時候的編碼規(guī)則構造出 StartKey 和 EndKey 便能包含對應分區(qū) Range 內所有的數(shù)據(jù),然后把這個范圍內的數(shù)據(jù)刪除,具體代碼實現(xiàn)在這里。

編碼規(guī)則:

Key: tablePrefix_rowPrefix_partitionID_rowID

startKey: tablePrefix_rowPrefix_partitionID

endKey: tablePrefix_rowPrefix_partitionID + 1

刪除了分區(qū),同時也將刪除該分區(qū)中的所有數(shù)據(jù)。如果刪除了分區(qū)導致分區(qū)不能覆蓋所有值,那么插入數(shù)據(jù)的時候會報錯。

Select 語句

Select 語句重點講 Select Partition 如何查詢的和分區(qū)裁剪(Partition Pruning),更詳細的可以看 TiDB 源碼閱讀系列文章(六)Select 語句概覽 。

一條 SQL 語句的處理流程,從 Client 接收數(shù)據(jù),MySQL 協(xié)議解析和轉換,SQL 語法解析,邏輯查詢計劃和物理查詢計劃執(zhí)行,到最后返回結果。那么對于分區(qū)表是如何查詢的表里的數(shù)據(jù)的,其實最主要的修改是 邏輯查詢計劃 階段,舉個例子:如果用上文中 employees 表作查詢, 在 SQL 語句的處理流程前幾個階段沒什么不同,但是在邏輯查詢計劃階段,rewriteDataSource 將 DataSource 重寫了變成 Union All 。每個 Partition id 對應一個 Table Reader。

select * from employees

等價于:

select * from (union all
select * from p0 where id < 1991
select * from p1 where id < 1996
select * from p2 where id < 2001
select * from p3 where id < MAXVALUE)

通過觀察?EXPLAIN 的結果可以證實上面的例子,如圖 1,最終物理執(zhí)行計劃中有四個 Table Reader 因為 employees 表中有四個分區(qū),Table Reader 表示在 TiDB 端從 TiKV 端讀取,cop task 是指被下推到 TiKV 端分布式執(zhí)行的計算任務。

圖 1:EXPLAIN 輸出

用戶在使用分區(qū)表時,往往只需要訪問其中部分的分區(qū), 就像程序局部性原理一樣,優(yōu)化器分析 FROMWHERE 子句來消除不必要的分區(qū),具體還要優(yōu)化器根據(jù)實際的 SQL 語句中所帶的條件,避免訪問無關分區(qū)的優(yōu)化過程我們稱之為分區(qū)裁剪(Partition Pruning),具體實現(xiàn)在 這里,分區(qū)裁剪是分區(qū)表提供的重要優(yōu)化手段,通過分區(qū)的裁剪,避免訪問無關數(shù)據(jù),可以加速查詢速度。當然用戶可以刻意利用分區(qū)裁剪的特性在 SQL 加入定位分區(qū)的條件,優(yōu)化查詢性能。

Insert 語句

Insert 語句 是怎么樣寫入 Table Partition ?

其實解釋這些問題就可以了:

普通表和分區(qū)表怎么區(qū)分?

插入數(shù)據(jù)應該插入哪個 Partition?

每個 Partition 的 RowKey 怎么編碼的和普通表的區(qū)別是什么?

怎么將數(shù)據(jù)插入到相應的 Partition 里面?

普通 Table 和 Table Partition 也是實現(xiàn)了 Table 的接口,load schema 在初始化 Table 數(shù)據(jù)結構的時候,如果發(fā)現(xiàn) tableInfo 里面沒有 Partition 信息,則生成一個普通的 tables.Table,普通的 Table 跟以前處理邏輯保持不變,如果 tableInfo 里面有 Partition 信息,則會生成一個 tables.PartitionedTable,它們的區(qū)別是 RowKey 的編碼方式:

每個分區(qū)有一個獨立的 Partition ID,Partition ID 和 Table ID 地位平等,每個 Partition 的 Row 和 index 在編碼的時候都使用這個 Partition 的 ID。

下面是 PartitionRecordKey 和普通表 RecordKey 區(qū)別。

分區(qū)表按照規(guī)則編碼成 Key-Value pair:

Key: tablePrefix_rowPrefix_partitionID_rowID

Value: [col1, col2, col3, col4]

普通表按照規(guī)則編碼成 Key-Value pair:

Key: tablePrefix_rowPrefix_tableID_rowID

Value: [col1, col2, col3, col4]

通過 locatePartition 操作查詢到應該插入哪個 Partition,目前支持 RANGE 分區(qū)插入到那個分區(qū)主要是通過范圍來判斷,例如在 employees 表中插入下面的 sql,通過計算范圍該條記錄會插入到 p3 分區(qū)中,接著調用對應 Partition 上面的 AddRecord 方法,將數(shù)據(jù)插入到相應的 Partition 里面。

INSERT INTO employees VALUES (1, "PingCAP TiDB", "2003-10-15"),

插入數(shù)據(jù)時,如果某行數(shù)據(jù)不屬于任何 Partition,則該事務失敗,所有操作回滾。如果 Partition 的 Key 算出來是一個 NULL,對于不同的 Partition 類型有不同的處理方式:

對于 Range Partition:該行數(shù)據(jù)被插入到最小的那個 Partition

對于 List partition:如果某個 Partition 的 Value List 中有 NULL,該行數(shù)據(jù)被插入那個 Partition,否則插入失敗

對于 Hash 和 Key Partition:NULL 值視為 0,計算 Partition ID 將數(shù)據(jù)插入到對應的 Partition

在 TiDB 分區(qū)表中分區(qū)字段插入的值不能大于表中 Range 值最大的上界,否則會報錯

End

TiDB 目前支持 Range 分區(qū)類型,具體以及更細節(jié)的可以看 這里。剩余其它類型的分區(qū)類型正在開發(fā)中,后面陸續(xù)會和大家見面,敬請期待。它們的源碼實現(xiàn)讀者屆時可以自行閱讀,流程和文中上述描述類似。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://systransis.cn/yun/17801.html

相關文章

  • TiDB 源碼閱讀系列文章二十四)TiDB Binlog 源碼解析

    摘要:在事務提交結束之后,事務可能提交成功,也可能提交失敗。需要把這個狀態(tài)告知如果發(fā)生了,那么輸出的類型就為,如果成功提交,那么輸出的類型就為。,當完成自己所有的狀態(tài)變更之后,會把的狀態(tài)改為。 作者:姚維 TiDB Binlog Overview 這篇文章不是講 TiDB Binlog 組件的源碼,而是講 TiDB 在執(zhí)行 DML/DDL 語句過程中,如何將 Binlog 數(shù)據(jù) 發(fā)送給 Ti...

    Alfred 評論0 收藏0
  • DM 源碼閱讀系列文章(七)定制化數(shù)據(jù)同步功能的實現(xiàn)

    摘要:作者王相本文為源碼閱讀系列文章的第七篇,在上篇文章中我們介紹了的實現(xiàn),主要包括目錄結構定義數(shù)據(jù)的處理流程主從切換支持的讀取等邏輯。本篇文章我們將會對的定制化數(shù)據(jù)同步功能進行詳細的講解。 作者:王相 本文為 DM 源碼閱讀系列文章的第七篇,在 上篇文章 中我們介紹了 relay log 的實現(xiàn),主要包括 relay log 目錄結構定義、relay log 數(shù)據(jù)的處理流程、主從切換支持、...

    leo108 評論0 收藏0

發(fā)表評論

0條評論

K_B_Z

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<