表管理接口概述
API | 描述 |
createTable | 建立表 |
deleteTable | 删除表 |
listTable | 列出執行個體下的所有表 |
updateTable | 更新表(在表被建立之後,動态的更改表的配置或預留吞吐量) |
describeTable | 擷取表的詳細資訊 |
上述API操作是Tablestore最基礎的API。官方提供了Java、Go、Node.js、Python、PHP、C#、C++語言的SDK。
建立表可以在控制台進行。在使用API進行建立的時候,需要指定表的配置資訊和預留吞吐量等資訊。
說明:
- 表格建立好後服務端有初始化時間,需要等待幾秒鐘才能對表進行讀寫,否則會出現異常
表限制
- 單個執行個體最多可以建立 64 張資料表
- 表名長度1-255 Bytes,需由[a-z, A-Z, 0-9]和下劃線(_)組成。首字元必須是字母或下劃線(_)
- 其它限制見: https://help.aliyun.com/document_detail/91524.html?spm=a2c4g.11186623.6.568.357f228382mAWN
參數說明
建立表的參數主要包括如下幾部分:
- TableMeta: 表的結構資訊,包含表的名稱以及表的主鍵定義
- TableOptions: 表的配置選項,用于配置TTL、MaxVersions等
- ReservedThroughput:表的預留讀寫吞吐量設定
表結構 TableMeta
參數 | 定義 | 說明 |
TableName | 表名 | 無 |
List | 表的主鍵定義 |
|
表配置 TableOptions
TTL | TimeToLive,資料存活時間 |
|
MaxVersions | 每個屬性列保留的最大版本數 |
|
MaxTimeDeviation | 寫入資料的時間戳與系統目前時間的偏差允許最大值 |
|
預留吞吐量 ReservedThroughtput
- ReservedThroughtput表的預留讀/寫吞吐量配置。
-
- 設定 ReservedThroughtput 後,表格存儲按照您預留讀/寫吞吐量進行計費。
- 當 ReservedThroughtput 大于 0 時,表格存儲會按照預留量和持續時間進行計費,超出預留的部分進行按量計費。更多資訊參見 計費 ,以免産生未期望的費用。
- 預設值為 0,即完全按量計費。
- 容量型執行個體的預留讀/寫吞吐量隻能設定為 0,不允許預留。
Java代碼示例
// 建立普通表(不使用索引等功能)
public void createTable() {
TableMeta tableMeta = new TableMeta(TABLE_NAME);
// 為主表添加主鍵列。
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_1", PrimaryKeyType.STRING));
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_2", PrimaryKeyType.INTEGER));
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_3", PrimaryKeyType.BINARY));
// 設定該主鍵為自增列
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_4", PrimaryKeyType.INTEGER, PrimaryKeyOption.AUTO_INCREMENT));
// 資料的過期時間,機關秒, -1代表永不過期,例如設定過期時間為一年, 即為 365 * 24 * 3600。
int timeToLive = -1;
// 儲存的最大版本數,設定為3即代表每列上最多儲存3個最新的版本。(如果使用索引,maxVersions隻能等于1)
int maxVersions = 3;
TableOptions tableOptions = new TableOptions(timeToLive, maxVersions);
CreateTableRequest request = new CreateTableRequest(tableMeta, tableOptions);
// 設定讀寫預留值,容量型執行個體隻能設定為0,高性能執行個體可以設定為非零值。
request.setReservedThroughput(new ReservedThroughput(new CapacityUnit(0, 0)));
client.createTable(request);
}
表設計相關技巧
分區鍵選擇
表格存儲Tablestore第一個主鍵是分區鍵,決定了資料分布式存儲的位置。分區鍵的選擇決定了資料是否均勻散列在不同的後端伺服器上。散列是分布式資料庫中常見的問題之一,資料的散列能夠避免熱點問題。是以在選擇主鍵的時候,首先要選好分區鍵。其中比較常用的兩種方式如下:
- 分區鍵可以選擇業務上比較分散的Key放到第一列,如userID、DeviceId等。如果每個使用者資料分布嚴重不均勻,則需要另外選擇其它字段。
- 如果分區鍵不好設計,可以對想要當做分區鍵的值拼接MD5,這樣能夠保證資料散列。
更多的設計技巧見兩篇表設計實踐。
表設計的最佳實踐、
表設計實踐資料生命周期TTL設計
資料生命周期(Time To Live,簡稱 TTL)是資料表的一個特性,即資料的存活時間,機關為秒。表格存儲會在背景對超過存活時間的資料進行清理,以減少使用者的資料存儲空間,降低存儲成本。
TTL特性能夠實作資料過期自動删除,是以在很多場景能夠用到,這些場景中随着時間的流逝資料的價值會降低,特别适合TTL。
- 輿情監控。如果使用者隻關心最近3個月的資訊,是以超過3個月的資料可以自動删除。
- 物流軌迹。物流軌迹的記錄資訊在使用者收到貨物後就失去了其大部分的價值,是以可以設定1個月的TTL,來節省大量的存儲費用。
- 系統日志。系統的運作日志大多數隻有在系統出問題時候才會檢視,而随着時間流逝,很早之前的系統日志也就失去了存在的價值,而這部分資料存儲在資料庫中會占用存儲成本,設定合适的TTL能夠自動将之前的資料删除。
TTL暫時僅支援主表,索引等還暫時不支援TTL特性。是以如果使用了二級索引或者多元索引,需要主表的TTL=-1,即永久不會失效,對于已經建立好表的使用者,可以通過 UpdateTable 接口動态更改主表的 TTL。
Java 示例代碼
public void updateTTL() {
UpdateTableRequest request = new UpdateTableRequest(TABLE_NAME);
int ttl = -1;
request.setTableOptionsForUpdate(new TableOptions(ttl));
client.updateTable(request);
}
主鍵自增
主鍵列自增功能是指若使用者指定某一列主鍵為自增列,在其寫入資料時,表格存儲會自動為使用者在這一列産生一個新的值,且這個值為同一個分區鍵下該列的最大值。
主鍵自增列的功能特性主要有生成數字ID且ID嚴格遞增保證順序,這個特性決定了許多場景能夠使用。
- 如電商網站的商品 ID、大型網站的使用者 ID等,這些場景中數值越大,表示該商品、使用者越新。
- 如論壇文章的 ID、聊天工具的消息 ID等消息保序的場景,這些場景需要嚴格保證消息遞增,不然使用者讀取到的順序就會亂序。舉個例子,假如使用者發朋友圈場景,使用者在1點5分11.1秒時刻發送了一個朋友圈記錄a,另一個使用者在1點5分11.2秒發送了一個朋友圈記錄b,則需要嚴格保證記錄b的id比記錄a的id大。主鍵自增在聊天系統IM中的應用見 Table Store主鍵列自增功能在IM系統中的應用
主鍵自增的一些限制:
- 表格存儲支援多個主鍵,第一個主鍵為分區鍵,分區鍵不允許設定為自增列,其它任一主鍵都可以設定為自增列。
- 每張表最多隻允許設定一個主鍵為自增列。
- 屬性列不能設定為自增列。
- 僅支援在建立表的時候指定自增列,對于已存在的表不支援建立自增列。
Java示例代碼
// 主鍵自增 建立主表
public void createTableWithPKAutoIncrement() {
TableMeta tableMeta = new TableMeta(TABLE_NAME + "AUTO_INCREMENT");
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_1", PrimaryKeyType.STRING));
// 設定該主鍵為自增列
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_autoI_increment", PrimaryKeyType.INTEGER, PrimaryKeyOption.AUTO_INCREMENT));
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_3", PrimaryKeyType.INTEGER));
TableOptions tableOptions = new TableOptions(-1, 1);
CreateTableRequest request = new CreateTableRequest(tableMeta, tableOptions);
client.createTable(request);
}
// 自增列的資料插入
public void putRow(){
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("pk_1", PrimaryKeyValue.fromString("test1"))
.addPrimaryKeyColumn("pk_auto_increment", PrimaryKeyValue.AUTO_INCREMENT)
.addPrimaryKeyColumn("pk_3", PrimaryKeyValue.fromLong(100))
.build();
RowPutChange rowPutChange = new RowPutChange(TABLE_NAME , primaryKey);
rowPutChange.addColumn("attr_1", ColumnValue.fromLong(100));
PutRowRequest request = new PutRowRequest(rowPutChange);
client.putRow(request);
}
删除表,隻需要指定表名字即可。
- 如果表中建立了多元索引,需要先删除多元索引才可以删除表。
public void deleteTable() {
DeleteTableRequest request = new DeleteTableRequest(TABLE_NAME);
client.deleteTable(request);
}
該API能夠列出目前執行個體下已建立的所有表的表名。
public void listTable() {
ListTableResponse response = client.listTable();
System.out.println("表的清單如下:");
for (String tableName : response.getTableNames()) {
System.out.println(tableName);
}
}
該API能夠動态的更改表的配置或預留吞吐量。可以隻修改配置或隻修改預留吞吐量,也可以一起修改。
- 該API調用頻率有限制,為每 2分鐘1次。
public void updateTable() {
UpdateTableRequest request = new UpdateTableRequest(TABLE_NAME);
// 修改預留吞吐
request.setReservedThroughputForUpdate(new ReservedThroughput(new CapacityUnit(0, 0)));
// 修改表的最大保留版本、TTL等
request.setTableOptionsForUpdate(new TableOptions(-1, 1));
client.updateTable(request);
}
該API可以獲得表的結構資訊(TableMeta)、配置資訊(TableOptions)和預留讀/寫吞吐量的情(ReservedThroughputDetails,包括調整時間)、表分區資訊等, 如圖所示。

public void describeTable() {
DescribeTableRequest request = new DescribeTableRequest(TABLE_NAME);
DescribeTableResponse response = client.describeTable(request);
TableMeta tableMeta = response.getTableMeta();
System.out.println("表的名稱:" + tableMeta.getTableName());
System.out.println("表的主鍵:");
for (PrimaryKeySchema schema : tableMeta.getPrimaryKeyList()) {
System.out.println("\t主鍵名字:" + schema.getName() + "\t主鍵類型:" + schema.getType()
+ "\t自增列:" + (schema.getOption() == null ? "false" : schema.getOption().equals(PrimaryKeyOption.AUTO_INCREMENT)));
}
System.out.println("預定義列資訊:");
for (DefinedColumnSchema schema : tableMeta.getDefinedColumnsList()) {
System.out.println("\t主鍵名字:" + schema.getName() + "\t主鍵類型:" + schema.getType());
}
System.out.println("二級索引資訊:");
for (IndexMeta meta : response.getIndexMeta()) {
System.out.println("\t索引名字:" + meta.getIndexName());
System.out.println("\t\t索引類型:" + meta.getIndexType());
System.out.println("\t\t索引主鍵:" + meta.getPrimaryKeyList());
System.out.println("\t\t索引預定義列:" + meta.getDefinedColumnsList());
}
TableOptions tableOptions = response.getTableOptions();
System.out.println("TableOptions:");
System.out.println("\t表的TTL:" + tableOptions.getTimeToLive());
System.out.println("\t表的MaxVersions:" + tableOptions.getMaxVersions());
ReservedThroughputDetails rtd = response.getReservedThroughputDetails();
System.out.println("預留吞吐量:");
System.out.println("\t讀:" + rtd.getCapacityUnit().getReadCapacityUnit());
System.out.println("\t寫:" + rtd.getCapacityUnit().getWriteCapacityUnit());
System.out.println("\t最近上調時間: " + new Date(rtd.getLastIncreaseTime() * 1000));
System.out.println("\t最近下調時間: " + new Date(rtd.getLastDecreaseTime() * 1000));
List<PrimaryKey> shardSplits = response.getShardSplits();
System.out.println("表分區資訊:");
for (PrimaryKey primaryKey : shardSplits) {
System.out.println("\t分裂點資訊: " + primaryKey.getPrimaryKeyColumnsMap());
}
}
專家服務
如有疑問或者需要更好的線上支援,歡迎加入釘釘群:“表格存儲公開交流群”(群号:23307953)。群内提供免費的線上專家服務,歡迎掃碼加入。