Azure Cosmos DB 中的資料模型化 \(部分機器翻譯\)
適用於:NoSQL
雖然無結構描述的資料庫 (例如 Azure Cosmos DB) 可讓您輕鬆地儲存及查詢非結構化和半結構化資料,但您應該花一些時間思考您的資料模型,以便在效能與擴充性方面獲得最佳的服務並獲得最低成本。
要如何儲存資料? 您的應用程式要如何擷取及查詢資料? 您的應用程式是大量讀取或大量寫入?
閱讀本文後,您將能夠回答下列問題:
- 什麼是資料模型化,以及為什麼應該關心?
- Azure Cosmos DB 中的模型化資料與關聯式資料庫有何不同?
- 如何表達非關聯式資料庫中的資料關聯性?
- 何時內嵌資料,以及何時連結至資料?
JSON 中的數字
Azure Cosmos DB 會將文件儲存為 JSON。 這表示在將數字儲存為 json 之前,是否需要仔細判斷是否必須將數字轉換成字串。 如果數字可能超出 IEEE 754 binary64 所述的雙精確度數字界限,則所有數字應該最好轉換為 String
。 Json 規格會指出為什麼使用此界限外數字通常會因為可能的互通性問題,而不是 JSON 中的理想做法。 這些問題尤其與分割區索引鍵資料行有關,因為其不可變,必須在資料移轉後才能變更。
內嵌資料
當您在 Azure Cosmos DB 中開始模型化資料時,請嘗試將您的實體視為以 JSON 文件表示的獨立式項目。
為了進行比較,我們先來看看我們可能會如何在關係資料庫中建立資料模型。 下列範例示範人員可能如何儲存在關聯式資料庫中。
使用關聯式資料庫時,策略是將您所有的資料標準化。 將您的資料正規化通常會牽涉到取得某個實體 (例如某個人),然後將其分解為離散的元件。 在範例中,人員可以有多個連絡詳細資料記錄,以及多個地址記錄。 您可以進一步擷取一般欄位 (例如類型),以進一步細分連絡人詳細資料。 相同的情況也適用於地址,每一筆記錄都可以是 Home 或 Business 類型。
將資料正規化的引導前提是在每個記錄資料上 避免儲存多餘的資料 ,而是參考資料。 在此範例中,若要讀取人員及其所有連絡詳細資料和地址,您需要使用「聯結」有效地在執行階段回寫 (或反正規化) 資料。
SELECT p.FirstName, p.LastName, a.City, cd.Detail
FROM Person p
JOIN ContactDetail cd ON cd.PersonId = p.Id
JOIN ContactDetailType cdt ON cdt.Id = cd.TypeId
JOIN Address a ON a.PersonId = p.Id
更新單一人員與其連絡詳細資料和地址需要跨許多個別資料表的寫入作業。
現在讓我們看看如何將相同的資料模型化為 Azure Cosmos DB 中的獨立實體。
{
"id": "1",
"firstName": "Thomas",
"lastName": "Andersen",
"addresses": [
{
"line1": "100 Some Street",
"line2": "Unit 1",
"city": "Seattle",
"state": "WA",
"zip": 98012
}
],
"contactDetails": [
{"email": "thomas@andersen.com"},
{"phone": "+1 555 555-5555", "extension": 5555}
]
}
使用此方法,我們已將人員記錄反正規化,方法是內嵌與人員相關的所有資訊 (例如他們的連絡詳細資料和地址) 到單一 JSON 文件。 此外,因為我們不受限於固定的結構描述,我們有彈性可進行一些動作,像是讓連絡詳細資料不同的圖形。
從資料庫擷取完整的人員記錄現在是針對單一容器和單一項目的單一讀取作業。 更新連絡詳細資料和地址等個人記錄,也是針對單一項目的單一寫入作業。
藉由反正規化資料,您的應用程式可能需要發出更少的查詢和更新以完成一般作業。
內嵌的時機
一般而言,使用內嵌的資料模型的時機為:
- 實體之間有包含的關聯性。
- 實體之間有 一對一些 關聯性。
- 內嵌的資料不常變更。
- 內嵌的資料在沒有繫結的情況下不會成長。
- 內嵌的資料會經常一起查詢。
注意
通常反正規化的資料模型可提供較佳的 讀取 效能。
不要內嵌的時機
雖然在 Azure Cosmos DB 中的經驗法則是對所有項目反正規化,並將所有資料內嵌至單一的項目,但是這可能會導致某些應該避免的情況。
取得此 JSON 程式碼片段。
{
"id": "1",
"name": "What's new in the coolest Cloud",
"summary": "A blog post by someone real famous",
"comments": [
{"id": 1, "author": "anon", "comment": "something useful, I'm sure"},
{"id": 2, "author": "bob", "comment": "wisdom from the interwebs"},
…
{"id": 100001, "author": "jane", "comment": "and on we go ..."},
…
{"id": 1000000001, "author": "angry", "comment": "blah angry blah angry"},
…
{"id": ∞ + 1, "author": "bored", "comment": "oh man, will this ever end?"},
]
}
如果我們要模型化一般的部落格或 CMS 系統,這可能是具有內嵌註解的文章實體的外觀。 此範例的問題在於註解陣列是 unbounded,表示任何單一文章可以具備的註解數目沒有 (實際) 的限制。 這可能會發生問題,因為項目的大小可能會無限地成長,因此您應該避免這種設計。
隨著項目大小的增加,透過網路傳輸資料以及大規模讀取和更新項目的能力,將會受到影響。
在此情況下,最好考慮使用下列資料模型。
Post item:
{
"id": "1",
"name": "What's new in the coolest Cloud",
"summary": "A blog post by someone real famous",
"recentComments": [
{"id": 1, "author": "anon", "comment": "something useful, I'm sure"},
{"id": 2, "author": "bob", "comment": "wisdom from the interwebs"},
{"id": 3, "author": "jane", "comment": "....."}
]
}
Comment items:
[
{"id": 4, "postId": "1", "author": "anon", "comment": "more goodness"},
{"id": 5, "postId": "1", "author": "bob", "comment": "tails from the field"},
...
{"id": 99, "postId": "1", "author": "angry", "comment": "blah angry blah angry"},
{"id": 100, "postId": "2", "author": "anon", "comment": "yet more"},
...
{"id": 199, "postId": "2", "author": "bored", "comment": "will this ever end?"}
]
此模型具有文件,其中有每個留言以及包含文章識別碼的屬性。 這樣可讓文章包含任意數量的留言,並且可以有效率地成長。 如果使用者想要查看不只最近的留言,將會查詢這個容器傳遞 postId,而這應該是留言容器的分割區索引鍵。
內嵌資料並不是好主意的另一種情況是在內嵌的資料經常跨項目使用,而且會經常變更時。
取得此 JSON 程式碼片段。
{
"id": "1",
"firstName": "Thomas",
"lastName": "Andersen",
"holdings": [
{
"numberHeld": 100,
"stock": { "symbol": "zbzb", "open": 1, "high": 2, "low": 0.5 }
},
{
"numberHeld": 50,
"stock": { "symbol": "xcxc", "open": 89, "high": 93.24, "low": 88.87 }
}
]
}
這可以代表個人的股票組合。 我們已選擇內嵌股票資料到每個組合文件。 在相關資料經常會變更的環境中,像是股票交易應用程式,內嵌經常變更的資料表示,每次交易股票時您便經常更新每個組合文件。
股票 zbzb 可能在單一日交易數百次,而上千名使用者的組合上可能有 zbzb。 如果使用此範例的資料模型,我們每天都必須多次更新數千個組合文件,這會導致系統無法妥善延展。
參考資料
內嵌資料於許多情況下可適用,但有時反正規化資料會造成更多問題,使得適得其反。 那我們現在該怎麼辦?
關聯式資料庫不是您可以建立實體之間的關聯性的唯一位置。 在文件資料庫中,文件中可以存在與其他文件中的資料相關的資訊。 我們不建議在 Azure Cosmos DB (或任何其他文件資料庫) 中建置比較適合關聯式資料庫的系統,但簡單的關聯性並沒有什麼不好的,而且可能很有用。
在 JSON 中,我們選擇使用先前的股票組合範例,但這次我們參考組合上的股票項目而不是加以內嵌。 如此一來,經常全天變更的股票項目,需要更新的唯一文件是單一股票文件。
Person document:
{
"id": "1",
"firstName": "Thomas",
"lastName": "Andersen",
"holdings": [
{ "numberHeld": 100, "stockId": 1},
{ "numberHeld": 50, "stockId": 2}
]
}
Stock documents:
{
"id": "1",
"symbol": "zbzb",
"open": 1,
"high": 2,
"low": 0.5,
"vol": 11970000,
"mkt-cap": 42000000,
"pe": 5.89
},
{
"id": "2",
"symbol": "xcxc",
"open": 89,
"high": 93.24,
"low": 88.87,
"vol": 2970200,
"mkt-cap": 1005000,
"pe": 75.82
}
不過,這個方法目前的缺點是您的應用程式是否需要在顯示人員的組合時顯示持有的每個股票的相關資訊;在此情況下,您必須對資料庫中進行多個來回行程,才能載入每個股票文件的資訊。 在這裡,我們決定提升全天經常發生之寫入作業的效率,但反而對此特定的系統效能影響較小的讀取作業有害。
注意
正規化的資料模型 可能需要更多來回行程 到伺服器。
外部索引鍵呢?
因為目前沒有條件約束、外部索引鍵之類的概念,您在文件中具有的任何文件間關聯性實際上是「弱式連結」,並且將不會由資料庫本身驗證。 如果您想要確定文件所參考的資料真的存在,您就需要在您的應用程式中這麼做,或在 Azure Cosmos DB 上透過使用伺服器端觸發程序或預存程序。
參考時機
一般而言,使用正規化資料模型的時機為:
- 代表 一對多 關聯性。
- 代表 多對多 關聯性。
- 相關資料 經常變更。
- 參考資料可能是 unbounded。
注意
通常正規化可提供較佳的 寫入 效能。
放置關聯性的位置為何?
關聯性的成長將有助於判斷用來儲存參考的文件。
如果我們觀察建立發行者和書籍模型的 JSON。
Publisher document:
{
"id": "mspress",
"name": "Microsoft Press",
"books": [ 1, 2, 3, ..., 100, ..., 1000]
}
Book documents:
{"id": "1", "name": "Azure Cosmos DB 101" }
{"id": "2", "name": "Azure Cosmos DB for RDBMS Users" }
{"id": "3", "name": "Taking over the world one JSON doc at a time" }
...
{"id": "100", "name": "Learn about Azure Cosmos DB" }
...
{"id": "1000", "name": "Deep Dive into Azure Cosmos DB" }
如果每個發行者書籍的數量很少而且成長有限,那麼,將書籍參考儲存在發行者文件內可能很有用。 不過,如果每個發行者的書籍數量無限,此資料模型會導致可變動、成長的陣列,如範例發行者文件所示。
切換項目位元會導致模型仍代表相同的資料,但現在可避免這些大型的可變動集合。
Publisher document:
{
"id": "mspress",
"name": "Microsoft Press"
}
Book documents:
{"id": "1","name": "Azure Cosmos DB 101", "pub-id": "mspress"}
{"id": "2","name": "Azure Cosmos DB for RDBMS Users", "pub-id": "mspress"}
{"id": "3","name": "Taking over the world one JSON doc at a time", "pub-id": "mspress"}
...
{"id": "100","name": "Learn about Azure Cosmos DB", "pub-id": "mspress"}
...
{"id": "1000","name": "Deep Dive into Azure Cosmos DB", "pub-id": "mspress"}
在此範例中,我們在發行者文件上捨棄無限制的集合。 我們在每個書籍文件上只有發行者的參考。
如何建立多對多關聯性的模型?
在關聯式資料庫 多對多 關聯性中,通常是與聯結資料表模型化,其只是將記錄從其他資料表聯結在一起。
您可能會想要使用文件複寫相同的項目,並產生看起來如下所示的資料模型。
Author documents:
{"id": "a1", "name": "Thomas Andersen" }
{"id": "a2", "name": "William Wakefield" }
Book documents:
{"id": "b1", "name": "Azure Cosmos DB 101" }
{"id": "b2", "name": "Azure Cosmos DB for RDBMS Users" }
{"id": "b3", "name": "Taking over the world one JSON doc at a time" }
{"id": "b4", "name": "Learn about Azure Cosmos DB" }
{"id": "b5", "name": "Deep Dive into Azure Cosmos DB" }
Joining documents:
{"authorId": "a1", "bookId": "b1" }
{"authorId": "a2", "bookId": "b1" }
{"authorId": "a1", "bookId": "b2" }
{"authorId": "a1", "bookId": "b3" }
這應該可行。 不過,載入其中一個作者的書籍,或載入書籍的作者,一律需要對資料庫進行至少兩個額外查詢。 一個對聯結文件的查詢,另一個查詢則用來擷取實際聯結的文件。
如果此聯結的作用只是在將兩組資料結合在一起,那麼為何不將其完全捨棄? 請思考一下下列範例。
Author documents:
{"id": "a1", "name": "Thomas Andersen", "books": ["b1", "b2", "b3"]}
{"id": "a2", "name": "William Wakefield", "books": ["b1", "b4"]}
Book documents:
{"id": "b1", "name": "Azure Cosmos DB 101", "authors": ["a1", "a2"]}
{"id": "b2", "name": "Azure Cosmos DB for RDBMS Users", "authors": ["a1"]}
{"id": "b3", "name": "Learn about Azure Cosmos DB", "authors": ["a1"]}
{"id": "b4", "name": "Deep Dive into Azure Cosmos DB", "authors": ["a2"]}
現在,如果我有作者,我立即會知道他們的書籍,而反之,如果我載入書籍文件,我就知道作者的識別碼。 這樣可以省下對聯結資料表的中繼查詢,減少您的應用程式必須進行的伺服器來回行程數目。
混合式資料模型
我們現在已注意到內嵌 (或反正規化) 與參考 (或正規化) 資料。 每個方法各有優缺點。
這不必然是二擇一,不妨多方嘗試。
根據您的應用程式特定的使用模式和工作負載,可能有時候混用內嵌和參考的資料有意義,而可能導致較簡單的應用程式邏輯與較少的伺服器來回行程,同時維持良好的效能等級。
請考慮下列 JSON。
Author documents:
{
"id": "a1",
"firstName": "Thomas",
"lastName": "Andersen",
"countOfBooks": 3,
"books": ["b1", "b2", "b3"],
"images": [
{"thumbnail": "https://....png"}
{"profile": "https://....png"}
{"large": "https://....png"}
]
},
{
"id": "a2",
"firstName": "William",
"lastName": "Wakefield",
"countOfBooks": 1,
"books": ["b1"],
"images": [
{"thumbnail": "https://....png"}
]
}
Book documents:
{
"id": "b1",
"name": "Azure Cosmos DB 101",
"authors": [
{"id": "a1", "name": "Thomas Andersen", "thumbnailUrl": "https://....png"},
{"id": "a2", "name": "William Wakefield", "thumbnailUrl": "https://....png"}
]
},
{
"id": "b2",
"name": "Azure Cosmos DB for RDBMS Users",
"authors": [
{"id": "a1", "name": "Thomas Andersen", "thumbnailUrl": "https://....png"},
]
}
這裡我們 (差不多) 看完了內嵌的模型,即來自其他實體的資料會內嵌在最上層的文件中,但參考其他資料。
如果您查看書籍文件,在查看作者陣列時就會看到一些有趣的欄位。 有一個 id
欄位,這是我們用來往回參考某個作者文件的欄位,也是正規化模型中的標準做法;但我們同時也有 name
和 thumbnailUrl
。 我們可以只使用 id
,並讓應用程式使用「連結」來向個別的作者文件取得其所需的任何額外資訊;但因為我們的應用程式會針對每個所顯示的書籍顯示作者名稱和縮圖圖片,我們可以透過對作者的某些資料進行反正規化,來免除對清單中的每個書籍向伺服器進行來回行程的必要性。
當然,如果作者的名稱變更,或他們想要更新其相片,我們便得更新其曾經發行的所有書籍;但由於作者應該不會經常變更其名稱,這對於我們的應用程式來說,是個可接受的設計決策。
範例中有預先計算的彙總值,可節省讀取作業費用高昂的處理。 在範例中,作者文件中內嵌的有些資料是在執行階段計算的資料。 每次發行新的書籍時,會建立書籍的文件 並且 將 countOfBooks 欄位設定為根據某位特定作者存在的書籍文件數目計算值。 在讀取繁重的系統中 (我們可以負擔執行寫入計算以最佳化讀取),這項最佳化將很適合。
由於 Azure Cosmos DB 支援多文件交易,因此模型現在能夠具有預先計算的欄位。 許多 NoSQL 存放區無法跨文件中執行交易,而因為這項限制而提倡「一律內嵌一切」的設計決策。 藉由 Azure Cosmos DB,您可以使用伺服器端觸發程序或預存程序,插入書籍並更新作者,全都在 ACID 交易內完成。 現在您不需在一份文件內嵌所有內容,只需要確保您的資料保持一致。
區分不同的文件類型
在某些情況下,您可能會想要在相同的集合中混合不同的文件類型;當您想要讓多個相關文件位於相同的分割區時,通常會發生這種情況。 例如,您可以將書籍和書籍評論放在相同的集合中,並依 bookId
將其分割。 在這種情況下,您通常需要使用可識別其類型的欄位將其新增至您的文件,以便加以區分。
Book documents:
{
"id": "b1",
"name": "Azure Cosmos DB 101",
"bookId": "b1",
"type": "book"
}
Review documents:
{
"id": "r1",
"content": "This book is awesome",
"bookId": "b1",
"type": "review"
},
{
"id": "r2",
"content": "Best book ever!",
"bookId": "b1",
"type": "review"
}
適用於 Azure Synapse Link 和 Azure Cosmos DB 分析存放區的資料模型
適用於 Azure Cosmos DB 的 Azure Synapse Link 是雲端原生的混合式交易和分析處理 (HTAP) 功能,可讓您對 Azure Cosmos DB 中的作業資料執行近即時分析。 Azure Synapse Link 會在 Azure Cosmos DB 與 Azure Synapse Analytics 之間建立緊密順暢的整合。
這項整合會透過 Azure Cosmos DB 分析存放區,以單欄方式呈現您的交易資料,以提供大規模分析,而不會影響您的交易工作負載。 此分析存放區適合用於大型操作資料的快速、符合成本效益的查詢,不需要複製資料,也不會影響交易工作負載的效能。 當您建立已啟用分析存放區的容器,或在現有容器上啟用分析存放區時,所有交易插入、更新和刪除都會近乎即時地與分析存放區同步處理,而不需要變更摘要或 ETL 作業。
有了 Azure Synapse Analytics,您現在可以從 Azure Synapse Analytics 直接連線到您的 Azure Cosmos DB 容器,並存取分析存放區,而不需要要求單位 (要求單位) 成本。 Azure Synapse Analytics 目前支援 Azure Synapse Link 搭配 Synapse Apache Spark 和無伺服器 SQL 集區。 如果您有全域散發的 Azure Cosmos DB 帳戶,則在啟用容器的分析存放區之後,該帳戶在所有區域都將可加以使用。
分析存放區自動結構描述推斷
雖然 Azure Cosmos DB 交易存放區是視為資料列導向的半結構化資料,但分析存放區具有單欄式和結構化格式。 這項轉換會使用分析存放區的結構描述推斷規則來自動為客戶進行。 轉換程序有一些限制:最大的巢狀層級數目、屬性的最大數目、不支援的資料類型等等。
注意
在分析存放區的內容中,我們將下列結構視為屬性:
- JSON 「元素」或 以
:
分隔的字串-值組。 - JSON 物件 (以
{
和}
分隔)。 - JSON 陣列 (以
[
和]
分隔)。
您可以使用下列技術,將結構描述推斷轉換的影響降到最低,並最大幅度提高分析功能。
正規化
由於透過 Azure Synapse Link 時,您可以使用 T-SQL 或 Spark SQL 在容器之間聯結,因此正規化變得毫無意義。 正規化的預期優點如下:
- 交易和分析存放區中的資料磁碟使用量較小。
- 交易較小。
- 每份文件的屬性較少。
- 具有較少巢狀層級的資料結構。
請注意,最後兩個因素 (較少的屬性和較少的層級) 有助於分析查詢的效能,但也會降低部分資料未在分析存放區中表示的機率。 如自動結構描述推斷規則一文所述,在分析存放區中表示的層級和屬性數目有一些限制。
正規化的另一個重要因素是,Azure Synapse 中的 SQL 無伺服器集區支援最多 1,000 個資料行的結果集,而公開的巢狀資料行也會計入該限制。 換句話說,分析存放區和 Synapse SQL 無伺服器集區的限制為 1,000 個屬性。
但是,由於反正規化是 Azure Cosmos DB 的重要資料模型技術,應該採取什麼動作? 答案是您必須找出交易和分析工作負載的正確平衡。
分割區索引鍵
您的 Azure Cosmos DB 分割區索引鍵 (PK) 不會用在分析存放區中。 現在您可以使用您所需的任何 PK,將分析存放區自訂分割區用於分析存放區的複本。 由於這項隔離,您可以針對交易資料選擇 PK,並將焦點放在資料擷取和點讀取,同時使用 Azure Synapse Link 來完成跨分割區查詢。 看看以下範例:
在假設的全域 IoT 案例中,device id
是不錯的 PK,因為所有裝置都有類似的資料量,而且您將不會有經常性存取層分割區的問題。 但是,如果您想要分析多個裝置的資料,例如「所有來自昨天的資料」或「每個城市的總計」,您可能會遇到問題,因為這些是跨分割區查詢。 這些查詢可能會損害您的交易效能,因為其會在要求單位中使用您的部分輸送量來執行。 但使用 Azure Synapse Link 時,您可以不花費要求單位成本來執行這些分析查詢。 分析存放區的單欄式格式已針對分析查詢進行最佳化,而 Azure Synapse Link 會套用這個特性,讓 Azure Synapse Analytics 執行階段發揮絕佳的效能。
資料類型和屬性名稱
自動結構描述推斷規則文章會列出支援的資料類型。 雖然不支援的資料類型會封鎖分析存放區中的標記法,但 Azure Synapse 執行階段可能會以不同方式處理支援的資料類型。 其中一個範例是:使用遵循 ISO 8601 UTC 標準的日期時間字串時,Azure Synapse 中的 Spark 集區會將這些資料行表示為字串,而 Azure Synapse 中的 SQL 無伺服器集區會將這些資料行表示為 varchar(8000)。
另一項挑戰是,Azure Synapse Spark 不會接受所有的字元。 在接受空白字元的情況下,不會有冒號、抑音符號和逗點等字元。 假設您的文件有一個名為 "First Name, Last Name" 的屬性。 這個屬性將會在分析存放區中表示,而 Synapse SQL 無伺服器集區可加以讀取而不會有問題。 但因為其是在分析存放區中,所以 Azure Synapse Spark 無法讀取分析存放區中的任何資料,包括所有其他屬性。 在一天結束時,如果您在其名稱中有一個屬性使用不支援的字元,就無法使用 Azure Synapse Spark。
資料壓平合併
在分析存放區中,Azure Cosmos DB 資料根層級中的所有屬性都會在分析存放區中表示為資料行,而您文件資料模型更深層級的其他所有屬性,則會以 JSON 形式表示,也會表示在巢狀結構中。 巢狀結構會要求從 Azure Synapse 執行階段進行額外的處理,以將資料以結構化格式壓平合併,在大型資料案例中可能會是一大挑戰。
文件在分析存放區中只會有兩個資料行,id
和 contactDetails
。 所有其他資料 (email
和 phone
) 都需要透過 SQL 函式來個別讀取,以進行額外的處理。
{
"id": "1",
"contactDetails": [
{"email": "thomas@andersen.com"},
{"phone": "+1 555 555-5555"}
]
}
文件在分析存放區中會有三個資料行,id
、email
和 phone
。 所有資料都可以直接存取為資料行。
{
"id": "1",
"email": "thomas@andersen.com",
"phone": "+1 555 555-5555"
}
資料分層
Azure Synapse Link 可讓您從下列方面降低成本:
- 在交易資料庫中執行的查詢較少。
- 針對資料擷取和點讀取最佳化的 PK,可減少資料磁碟使用量、經常性存取層分割案例和分割區。
- 由於分析存留時間 (attl) 與交易存留時間 (tttl) 無關,因此資料會分層。 您可以在交易存放區中保留幾天、數周、數個月的交易資料,並將資料保留在分析存放區數年或永久保存。 分析存放區的單欄式格式會帶來自然資料壓縮,從 50% 高達 90%。 而其每 GB 的成本是交易存放區實際價格的大約 10%。 如需目前備份限制的詳細資訊,請參閱分析存放區概觀。
- 沒有任何 ETL 作業在您的環境中執行,這表示您不需要為其佈建要求單位。
控制的備援
這是在資料模型已經存在且無法變更情況下的絕佳替代方案。 由於自動結構描述推斷規則,例如巢狀層級的限制或屬性的最大數目,因此現有的資料模型無法妥善放入分析存放區。 如果這是您的情況,您可以使用 Azure Cosmos DB 變更摘要將資料複寫到另一個容器,套用 Azure Synapse Analytics 易記資料模型所需的轉換。 看看以下範例:
案例
容器 CustomersOrdersAndItems
用來儲存線上訂單,包括客戶和項目詳細資料:帳單地址、交貨地址、交貨方法、交貨狀態、項目價格等等。只會顯示前 1,000 個屬性,而且金鑰資訊不會包含在分析存放區中,因此會封鎖 Azure Synapse Link 的使用。 容器具有數 PB 的記錄,因此無法變更應用程式及重新建模資料。
問題的另一個方面是巨量資料量。 分析部門經常使用數十億個資料列,而無法使用 tttl 來刪除舊的資料。 由於分析需求,在交易資料庫中維護整個資料歷程記錄會強制其不斷增加要求單位佈建,進而影響成本。 交易和分析工作負載會同時競爭相同的資源。
怎麼辦?
具有變更摘要的解決方案
- 工程小組決定使用變更摘要來填入三個新的容器:
Customers
、Orders
和Items
。 使用變更摘要時,其會將資料正規化和壓平合併。 從資料模型中移除不必要的資訊,而且每個容器都有接近 100 個屬性,可避免因為自動結構描述推斷限制而造成資料遺失。 - 這些新的容器已啟用分析存放區,且現在分析部門正在使用 Synapse Analytics 來讀取資料,並減少在 Synapse Apache Spark 和無伺服器 SQL 集區中發生分析查詢之後的要求單位使用量。
- 容器
CustomersOrdersAndItems
現在已將 tttl 設定為只保留資料六個月,這會使另一個要求單位使用量減少,因為 Azure Cosmos DB 中的每 GB 至少有一個要求單位。 較少的資料、較少的要求單位。
重要心得
本文的重點在於了解資料模型在無結構描述環境中十分重要。
正如同沒有單一方法可表示螢幕上的資料片段,沒有單一方法可為您的資料建立模型。 您需要了解您的應用程式,以及其如何產生、取用及處理資料。 然後,藉由套用一些此處所提供的指導方針,您可以設定相關的建立模型,來處理您的應用程式的立即需求。 當您的應用程式需要進行變更時,您可以使用無結構描述資料庫的彈性來納入變更,並輕鬆進化您的資料模型。