資料操縱語言 (DML) 和變異是 Spanner 中的兩個 API,可用於修改資料。兩者都提供類似的資料操控功能。本頁將比較這兩種做法。
什麼是資料操縱語言 (DML)?
您可以使用 Spanner 的資料操縱語言 (DML),透過 INSERT、UPDATE 和 DELETE 陳述式操縱資料庫資料表中的資料。您可以使用用戶端程式庫、Google Cloud 控制台和 gcloud spanner 執行 DML 陳述式。
Spanner 提供下列兩種 DML 執行實作方式,各有不同的屬性。
標準 DML - 適用於標準線上交易處理 (OLTP) 工作負載。
如需詳細資訊 (包括程式碼範例),請參閱「使用 DML」一文。
分區 DML - 專為大量更新和刪除而設計,如下列範例所示。
定期清理和垃圾回收。例如刪除舊資料列或將資料欄設定為 NULL。
對具有預設值的新資料欄進行補充作業。例如使用 UPDATE 陳述式,將值為 NULL 的新資料欄設為 False。
如需更多資訊 (包括程式碼範例),請參閱「使用分區 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」(已更新 0 筆記錄) 。這是因為這是因為我們使用 Mutations 所做的變更,在交易修訂前,後續陳述式都無法看到。理想情況下,我們應等到交易結束時,才將寫入內容放在緩衝區。
後續步驟
瞭解如何使用 DML 修改資料。
瞭解如何使用變異修改資料。
如要找出交易的突變次數,請參閱「擷取交易的修訂統計資料」。