共用方式為


Azure Cosmos DB 中的資料建模

適用於:NoSQL

雖然無結構描述的資料庫 (例如 Azure Cosmos DB) 可讓您輕鬆地儲存及查詢非結構化和半結構化資料,但您應該花一些時間思考您的資料模型,以便在效能與擴充性方面獲得最佳的服務並獲得最低成本。

要如何儲存資料? 您的應用程式要如何擷取及查詢資料? 您的應用程式的負載是偏向讀取還是偏向寫入?

閱讀本文後,您將能夠回答下列問題:

  • 什麼是資料模型化,以及為什麼應該關心?
  • Azure Cosmos DB 中的模型化資料與關聯式資料庫有何不同?
  • 如何表達非關聯式資料庫中的資料關聯性?
  • 何時內嵌資料,以及何時連結至資料?

JSON 中的數字

Azure Cosmos DB 會將文件儲存為 JSON。 這表示在將數字儲存為 json 之前,有必要仔細判斷是否需要將數字轉換成字串。 如果數字可能超出 IEEE 754 binary64 所述的雙精確度數字界限,則所有數字最好應轉換為 StringJson 規格明確說明了為什麼在一般情況下使用超出此界限的數字在 JSON 中是一種不理想的做法,因為這可能導致互通性問題。 這些問題尤其與分割區鍵資料行有關,因為其不可變,並且必須進行資料移轉才能進行變更。

內嵌資料

當您在 Azure Cosmos DB 中開始模型化資料時,請嘗試將您的實體視為以 JSON 文件表示的獨立式項目

為了進行比較,我們先來看看我們可能會如何在關係資料庫中建立資料模型。 下列範例示範人員可能如何儲存在關聯式資料庫中。

關聯式資料庫模型

使用關聯式資料庫時,策略是將您所有的資料標準化。 將您的資料正規化通常會牽涉到取得某個實體 (例如某個人),然後將其分解為離散的元件。 在範例中,人員可以有多個連絡詳細資料記錄,以及多個地址記錄。 您可以進一步擷取一般欄位 (例如類型),以進一步細分連絡人詳細資料。 相同的情況也適用於地址,每一筆記錄都可以是 HomeBusiness 類型。

將資料正規化的引導前提是每個紀錄中避免儲存多餘的資料,而是參考已存在的資料。 在此範例中,若要讀取人員及其所有連絡詳細資料和地址,您需要使用「聯結」有效地在執行階段回寫 (或反正規化) 資料。

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 上透過使用伺服器端觸發程序或預存程序。

參考時機

一般而言,使用正規化資料模型的時機為:

  • 代表一對多關聯性。
  • 代表多對多關聯性。
  • 相關資料 經常變更
  • 參考資料可能是無限制的

附註

通常正規化可提供較佳的 寫入 效能。

關聯性應置於何處?

關聯性的成長將有助於判斷用來儲存參考的文件。

如果我們觀察為出版商和書籍建立模型的 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 欄位,這是我們用來往回參考某個作者文件的欄位,也是正規化模型中的標準做法;但我們同時也有 namethumbnailUrl。 我們可以只使用 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 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 執行階段進行額外的處理,以將資料以結構化格式壓平合併,在大型資料案例中可能會是一大挑戰。

文件在分析存放區中只會有兩個資料行,idcontactDetails。 所有其他資料 (emailphone) 都需要透過 SQL 函式來個別讀取,以進行額外的處理。


{
    "id": "1",
    "contactDetails": [
        {"email": "thomas@andersen.com"},
        {"phone": "+1 555 555-5555"}
    ]
}

文件在分析存放區中會有三個資料行,idemailphone。 所有資料都可以直接以資料行的形式存取。


{
    "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 來刪除舊的資料。 由於分析需求,在交易資料庫中維護整個資料歷程記錄會強制其不斷增加要求單位佈建,進而影響成本。 交易和分析工作負載會同時競爭相同的資源。

怎麼辦?

具有變更摘要的解決方案

  • 工程小組決定使用變更摘要來填入三個新的容器:CustomersOrdersItems。 使用 Change Feed 可對資料進行正規化和壓平。 從資料模型中移除不必要的資訊,而且每個容器都有接近 100 個屬性,可避免因為自動結構描述推斷限制而造成資料遺失。
  • 這些新的容器已啟用分析儲存,現在分析部門正在使用 Synapse Analytics 來讀取資料,因為分析查詢是在 Synapse Apache Spark 和無伺服器 SQL 集區中進行,所以請求單位的使用量得以減少。
  • 容器 CustomersOrdersAndItems 現在已將 tttl 設定為只保留資料六個月,從而進一步降低要求單位使用量,因為在 Azure Cosmos DB 中,每 GB 至少有一個要求單位。 較少的資料、較少的要求單位。

重要心得

本文的重點在於了解資料模型在無結構描述環境中十分重要。

正如同沒有單一方法可表示螢幕上的資料片段,沒有單一方法可為您的資料建立模型。 您需要了解您的應用程式,以及其如何產生、取用及處理資料。 然後,藉由套用一些此處所提供的指導方針,您可以開始建立一個模型,以應對您的應用程式的迫切需求。 當您的應用程式需要進行變更時,您可以使用無結構描述資料庫的彈性來納入變更,並輕鬆進化您的資料模型。