資料操縱語言 (DML) 和異動是 Spanner 中的兩個 API,可用於修改資料。兩者提供的資料操作功能類似。本頁面會比較這兩種方法。
什麼是 data manipulation language (DML)?
Spanner 的資料操縱語言 (DML) 可讓您使用 INSERT、UPDATE 和 DELETE 陳述式,操縱資料庫資料表中的資料。您可以使用用戶端程式庫、Google Cloud 控制台和 gcloud spanner 執行 DML 陳述式。
Spanner 提供下列兩種 DML 執行方式,各有不同的屬性。
標準 DML:適用於標準線上交易處理 (OLTP) 工作負載。
如需更多資訊 (包括程式碼範例),請參閱「使用 DML」。
分區 DML:專為大量更新和刪除作業設計,如下列範例所示。
定期清理和垃圾收集。例如刪除舊資料列或將資料欄設為 NULL。
對具有預設值的新資料欄進行補充作業。例如,使用 UPDATE 陳述式將新資料欄的值設為 False (如果值為 NULL)。
如需更多資訊 (包括程式碼範例),請參閱「使用分區 DML」。
如果需要執行大量寫入作業,但不需要讀取作業,也不需要原子交易,可以使用批次寫入。詳情請參閱「使用批次寫入修改資料」。
什麼是變異?
異動代表 Spanner 以不可分割的方式,對資料庫中不同資料列和資料表套用的一連串插入、更新和刪除作業。您可以在異動中加入適用於不同資料列或不同資料表的作業。定義一或多個包含一或多個寫入作業的異動後,您必須套用異動,才能提交寫入作業。每項變更都會按照新增至異動的順序套用。
如需更多資訊 (包括程式碼範例),請參閱「使用異動插入、更新及刪除資料」。
DML 與異動的功能比較
下表匯總常見資料庫作業和功能的 DML 和異動支援。
| 作業 | DML | 異動 |
|---|---|---|
| 插入資料 | 支援 | 支援 |
| 刪除資料 | 支援 | 支援 |
| 更新資料 | 支援 | 支援 |
| 插入或忽略資料 | 支援 | 不支援 |
| 讀取寫入內容 (RYW) | 支援 | 不支援 |
| 插入或更新資料 (Upsert) | 支援 | 支援 |
| SQL 語法 | 支援 | 不支援 |
| 限制檢查 | 每個陳述式後 | 提交時 |
| 異動限制強制執行 (含索引) | 每個陳述式 (執行後重設) | 每次修訂 (累計) |
DML 和異動對下列功能的支援有所不同:
讀取自己的寫入內容:讀取有效交易中未提交的結果。使用 DML 陳述式所做的變更,會顯示在同一交易中的後續陳述式。這與使用異動不同,異動在提交前,任何讀取作業 (包括在同一交易中執行的讀取作業) 都無法看到變更。這是因為交易中的異動會在本機 (用戶端) 緩衝處理,並在執行修訂作業時傳送至伺服器。因此,在同一筆交易中,SQL 或 DML 陳述式不會顯示修訂要求中的異動。
限制檢查:Spanner 會在每個 DML 陳述式後檢查限制。這與使用異動不同,Spanner 會在用戶端緩衝異動,直到提交為止,並在提交時檢查限制。在每個 DML 陳述式後評估限制,可確保 Spanner 在同一交易中,後續查詢傳回的資料與結構定義一致。
異動限制:DML 的異動限制為每個陳述式 80,000 次 (包括索引),並會在陳述式執行後重設。這樣一來,單一交易就能執行多個 DML 陳述式,只要單一陳述式不超過上限,總共可超過 80,000 項異動。Mutation API 只能做為修訂作業的一部分使用,因此 80,000 次異動 (包括索引) 的限制是修訂中所有異動的累計值。這兩種方法都受限於 100 MiB 的交易大小限制。
SQL 語法:DML 提供傳統的資料操作方式。您可以使用 DML API,重複運用 SQL 技能來修改資料。
最佳做法:避免在同一筆交易中混用 DML 和異動
如果交易在修訂要求中同時包含 DML 陳述式和異動,Spanner 會先執行 DML 陳述式,再執行異動。為避免在用戶端程式庫程式碼中考量執行順序,您應在單一交易中使用 DML 陳述式或異動,但不能同時使用兩者。
以下 Java 範例說明可能令人意外的行為。程式碼會使用 Mutation API,在 Albums 中插入兩個資料列。接著,程式碼片段會呼叫 executeUpdate() 來更新新插入的資料列,並呼叫 executeQuery() 來讀取更新後的專輯。
static void updateMarketingBudget(DatabaseClient dbClient) {
dbClient
.readWriteTransaction()
.run(
new TransactionCallable<Void>() {
@Override
public Void run(TransactionContext transaction) throws Exception {
transaction.buffer(
Mutation.newInsertBuilder("Albums")
.set("SingerId")
.to(1)
.set("AlbumId")
.to(1)
.set("AlbumTitle")
.to("Total Junk")
.set("MarketingBudget")
.to(800)
.build());
transaction.buffer(
Mutation.newInsertBuilder("Albums")
.set("SingerId")
.to(1)
.set("AlbumId")
.to(2)
.set("AlbumTitle")
.to("Go Go Go")
.set("MarketingBudget")
.to(200)
.build());
// This UPDATE will not include the Albums inserted above.
String sql =
"UPDATE Albums SET MarketingBudget = MarketingBudget * 2"
+ " WHERE SingerId = 1";
long rowCount = transaction.executeUpdate(Statement.of(sql));
System.out.printf("%d records updated.\n", rowCount);
// Read a newly updated record.
sql =
"SELECT SingerId, AlbumId, AlbumTitle FROM Albums"
+ " WHERE SingerId = 1 AND MarketingBudget < 1000";
ResultSet resultSet =
transaction.executeQuery(Statement.of(sql));
while (resultSet.next()) {
System.out.printf(
"%s %s\n",
resultSet.getString("FirstName"),
resultSet.getString("LastName"));
}
return null;
}
});
}
如果執行這段程式碼,您會看到「0 records updated」。這是因為這是因為使用 Mutations 進行的變更,在交易提交前,後續陳述式都無法看到。理想情況下,我們應該只在交易結束時才進行緩衝寫入。
後續步驟
瞭解如何使用 DML 修改資料。
瞭解如何使用異動修改資料。
如要查看交易的異動次數,請參閱「擷取交易的修訂版本統計資料」。