Azure DevOps 的 OData Analytics 查詢指導方針

Azure DevOps 服務 |Azure DevOps Server |Azure DevOps Server 2022

擴充功能開發人員可以遵循本文中提供的指導方針,針對 Azure DevOps 分析設計高效的 OData 查詢來受益。 遵循這些指導方針有助於確保查詢有良好的運行時間和資源耗用量效能。 不符合這些指導方針的查詢可能會導致效能不佳,且報表等候時間很長、查詢超過允許的資源耗用量或服務封鎖。

注意

Azure DevOps Services 內所有服務的生產環境中會自動啟用及支援 Analytics 服務。 Power BI 整合 及存取 Analytics 服務的 OData 摘要 已正式推出。 建議您使用 Analytics OData 摘要並提供意見反應。

可用的數據與版本相關。 OData API 的最新支援版本是 v2.0,而最新的預覽版本是 v4.0-preview。 如需詳細資訊,請參閱 OData API 版本控制。

注意

Azure DevOps Server 2020 和更新版本的所有新專案集合都會在生產環境中自動安裝並支援 Analytics 服務。 Power BI 整合 及存取 Analytics 服務的 OData 摘要 已正式推出。 建議您使用 Analytics OData 摘要並提供意見反應。 如果您從 Azure DevOps Server 2019 升級,您可以在升級期間安裝 Analytics 服務。

可用的數據與版本相關。 OData API 的最新支援版本是 v2.0,而最新的預覽版本是 v4.0-preview。 如需詳細資訊,請參閱 OData API 版本控制。

這些指南是我們的建議,前面附有詞彙 DO、CONSIDER、AVOID 和 DON'T。 Analytics 強制執行的限制性規則包含 [BLOCKED] 前置詞。 您應該瞭解不同解決方案之間的取捨。 在某些情況下,您可能會有強制違反一或多個指導方針的數據需求。 這種情況應該很少見。 我們建議您有明確且令人信服的理由來進行這類決策。

提示

本檔中所示的範例是以 Azure DevOps Services URL 為基礎。 使用替代方案替代內部部署版本。

https://{servername}:{port}/tfs/{OrganizationName}/{ProjectName}/_odata/{version}/

錯誤和警告訊息

✔️ DO 檢視 OData 回應警告

您執行的每個查詢都會根據一組預先定義的規則進行檢查。 違規會傳回 OData 回應,如下@vsts.warnings。 請檢閱這些警告,因為它們提供如何改善查詢的目前和內容敏感性資訊。

{
  "@odata.context": "https://{OrganizationName}.tfsallin.net/_odata/v1.0/$metadata#WorkItems",
  "@vsts.warnings": [
    "The specified query does not include a $select or $apply clause which is recommended for all queries."
  ],
  ...
}

請檢閱 OData 錯誤訊息

違反 OData 錯誤規則的查詢會導致 400 (要求錯誤) 狀態代碼的回應失敗。 關聯訊息不會出現在@vsts.warnings屬性內。 相反地,它們會在 JSON 回應中的 屬性中 message 產生錯誤訊息。

{
  "error": {
  "code": "0",
  "message": "The query specified in the URI is not valid. The Snapshot tables in Analytics are intended to be used only in an aggregation."
  }
}

限制

可執行動作

考慮

封鎖

避免

✔️ DO 將查詢限制為您可以存取的專案

如果您的查詢以您沒有存取權的項目數據為目標,查詢會傳回「專案存取遭拒」訊息。 為了確保你有權限,請將 檢視分析 權限設定為「允許」,適用於你查詢的所有專案。 如需詳細資訊,請參閱 存取分析所需的許可權。

如果您沒有專案的存取權,會顯示下列訊息:

查詢結果包含一或多個您沒有存取權的項目中的數據。 新增一或多個專案篩選條件,以指定您在 『WorkItems』 實體中可以存取的專案。 如果您使用$expand或導覽屬性,則這些實體需要專案篩選條件。

若要解決此問題,您可以明確新增項目篩選,或使用 專案範圍端點 ,如本文稍後所述。

例如,下列查詢會擷取屬於名為 {projectSK1} 和 {projectSK2}之專案的工作項目。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=ProjectSK eq {projectSK1} or ProjectSK eq {projectSK2}
  &$select=WorkItemId, Title

✔️ 如果您的展開可能包含其他可能無法存取的專案,請在 $expand 子句中指定專案篩選。

當您展開瀏覽屬性時,您最終有可能參考來自其他無法存取之項目的數據。 如果您參考無法存取的數據,您會收到先前所列的相同錯誤訊息:「 查詢結果包含一或多個項目中的數據...」。 同樣地,您可以新增明確的專案篩選來控制展開的數據,以解決此問題。

您可以在一般 $filter 子句中執行此動作,以取得簡單的導覽屬性。 例如,下列查詢會明確要求 WorkItemLinks 連結及其目標存在於相同專案中的位置。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemLinks?
  $filter=ProjectSK eq {projectSK} and TargetWorkItem/ProjectSK eq {projectSK}
  &$select=LinkTypeReferenceName, SourceWorkItemId, TargetWorkItemId
  &$expand=TargetWorkItem($select=WorkItemId, Title)

相反地,您可以將篩選器移至$filter子句中的$expand擴展選項。 不過,它會變更查詢的語意。 例如,下列查詢會從指定專案取得所有連結,而且只有在目標存在於相同專案中時,才會有條件地展開目標。 雖然有效,但這種方法可能會造成混淆,因為可能很難判斷屬性未展開是因為它是 null ,還是因為它已被篩選掉。只有在您確實需要這種特定行為時,才使用此解決方案。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemLinks?
  $filter=ProjectSK eq {projectSK}
  &$select=LinkTypeReferenceName, SourceWorkItemId, TargetWorkItemId
  &$expand=TargetWorkItem($filter=ProjectSK eq {projectSK}; $select=WorkItemId, Title)

當您使用選項,時,例如在實體集中使用的 expand 集合屬性時,這會很有用。 例如,下列查詢會傳回指定專案的所有工作項目,以及屬於相同專案的所有子項目。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=ProjectSK eq {projectSK}
  &$select=WorkItemId, Title
  &$expand=Children($filter=ProjectSK eq {projectSK}; $select=WorkItemId, Title)

如果您將以下屬性之一擴展,請指定篩選器:

  • WorkItems 實體集: Parent、 Children
  • WorkItemLinks 實體集: TargetWorkItem。

✔️ 請考慮使用專案範圍的端點進行查詢

如果您對單一項目的資料感興趣,建議您使用項目範圍的 OData 端點(/{ProjectName}/_odata/v1.0)。 它可避免上述兩節所述的問題,並將數據隱含地篩選至一個專案、參考的實體集,以及所有展開的導覽屬性。

透過此簡化,上一節的查詢可以重寫為下列形式。 expand 子句中的篩選不僅消失,對主要實體集的篩選也已不再需要。

https://analytics.dev.azure.com/{OrganizationName}/{ProjectName}/_odata/{version}//WorkItemLinks?
  &$select=LinkTypeReferenceName, SourceWorkItemId, TargetWorkItemId
  &$expand=TargetWorkItem($select=WorkItemId, Title)

工作專案子系的查詢也較短且更簡單。

https://analytics.dev.azure.com/{OrganizationName}/{ProjectName}/_odata/{version}//WorkItems?
  &$select=WorkItemId, Title
  &$expand=Children($select=WorkItemId, Title)

只有當焦點是來自單一項目的數據時,您才能套用此解決方案。 針對跨項目報告,您必須使用上一節所述的篩選策略。

✔️ 如果您的查詢超過使用量限制,請等候或停止作業

如果您執行許多查詢,或查詢需要執行許多資源,您可能會超過服務限制並暫時遭到封鎖。 如果您超過服務限制,請停止作業,因為您傳送的下一個查詢失敗並出現相同的錯誤訊息。

因為命名空間 '{namespace}' 中的資源 '{resource}' 使用量超過,所以封鎖了要求。

如需速率限制的詳細資訊,請參閱 速率限制。 若要瞭解如何設計有效率的 OData 查詢,請參閱 本文稍後的 效能指導方針。

✔️ 如果您的查詢因逾時而失敗,請等候或停止作業

類似於超過使用量限制,如果您的查詢逾時,您應該等候或停止作業。 它可能會發出暫時性問題信號,因此您可以重試一次,以查看問題是否解決。 不過,持續性逾時表示查詢可能過於複雜而無法執行。 進一步的重試只會導致超過使用限制,而您會被封鎖。

TF400733:請求已被取消:請求已超過請求逾時,請再試一次。

逾時表示查詢需要優化。 若要瞭解如何設計有效率的 OData 查詢,請參閱 本文稍後的效能指導方針 。

❌ [BLOCKED] 請勿將快照集實體用於匯總以外的其他用途

具有後綴的 Snapshot 快照集實體集是特殊的,因為它們會模型化為 每日快照集。 您可以使用它們來取得實體的狀態,就如同它們在過去每天結束時的狀態一樣。 例如,如果您查詢 WorkItemSnapshot 並篩選到單一 WorkItemId,則自工作專案建立之後,您每天都會取得一筆記錄。 直接載入所有這些數據會很昂貴,而且很可能超過使用量限制並遭到封鎖。 不過,允許和建議對這些實體進行匯總。 事實上,快照實體集的設計是以聚合情境為考量。

例如,下列查詢會依日期取得工作項目的數目,以觀察其在 2020 年 1 月的增長情況。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemSnapshot?
  $apply=
    filter(DateSK ge 20200101 and DateSK le 20200131)/
    groupby((DateSK), aggregate($count as Count))

如需匯總的詳細資訊,請參閱 匯總數據。

✔️ 當您在快照資料表上進行匯總時,請在子句中包含 DateSK 或 DateValue 欄位,或使用 groupby。

由於所有快照集實體都會模型化為 每日快照集數據表,因此您應該一律在 grouping 子句中包含其中一個日屬性 (DateSK 或 DateValue)。 否則,結果可能會被不當的增大。

例如,如果您只依 WorkItemSnapshotAssignedTo 屬性分組,並以計數進行匯總,則指派給人員的所有工作項目數目都會乘以使用中每個工作分派的天數。 雖然您可能有想要的結果,但這類案例很少見。

❌ [BLOCKED] 請勿在資源路徑中使用實體鍵來進行實體尋址

OData 語法可讓您直接在 URL 區段中包含其索引鍵,以存取特定實體。 如需詳細資訊,請參閱 OData 4.0 版。第 2 部分:URL 慣例 - 4.3 尋址實體。 雖然 OData 允許這類尋址,但 Analytics 會加以封鎖。 在查詢中包含會導致下列錯誤。

URI 中指定的查詢無效。 分析不支援像 WorkItems(Id)或 WorkItem(Id)/AssignedTo 這樣的索引鍵或屬性導覽。 如果您在PowerBI中收到該錯誤,請重寫您的查詢,以避免產生 N+1 問題的不正確折疊。

錯誤訊息指出,某些用戶端工具可能會濫用直接實體尋址。 這類用戶端可能會選擇個別查詢每個實體,而不是在單一要求中載入所有數據。 不建議這種做法,因為可能會導致大量要求。 相反地,建議您使用明確的實體位址,如下一節所述。

✔️ DO 明確指定篩選子句中的實體

如果您想要擷取單一實體的數據,您應該使用與實體集合相同的方法,並在 子句中 $filter 明確定義篩選。

例如,下列查詢會依其標識碼取得單一工作專案。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=WorkItemId eq {id}
  &$select=WorkItemId, Title

如果您不確定應該包含在這類篩選中的屬性,您可以在元數據中查閱它。 請參閱 建構適用於分析的 OData 查詢、URL 元件以查詢元數據。 屬性位於 EntityType 的 Key 元素中。 例如,WorkItemId 和 Revision 是 WorkItemRevision 實體的關鍵欄位。

<EntityType Name="WorkItemRevision">
  <Key>
    <PropertyRef Name="WorkItemId"/>
    <PropertyRef Name="Revision"/>
  </Key>
  [...]
</EntityType>

❌[BLOCKED] 禁止在RevisionsWorkItem實體上擴展

分析數據模型不允許特定類型的擴充。 其中一個可能令某些人驚訝的是 WorkItem 實體上的 Revisions 集合屬性。 如果您嘗試展開此屬性,您會收到下列錯誤訊息。

URI 中指定的查詢無效。 屬性 'Revisions' 不能用於$expand查詢選項中。

已實施這項限制,用以鼓勵所有人使用建議的解決方案,從 WorkItemRevisions 中擷取修訂,如下一節所述。

✔️ DO 使用 WorkItemRevisions 實體集來載入指定工作專案的所有修訂

WorkItemRevisions每次您想要擷取工作專案或工作專案集合的完整歷程記錄時,請使用 。

例如,下列查詢會傳回具有 {id} 標識符之工作專案的所有修訂。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemRevisions?
  $filter=WorkItemId eq {id}
  &$select=WorkItemId, Title

如果您關心符合特定準則的所有工作專案的完整歷程記錄,請使用導覽屬性上的 WorkItem 篩選來表示它。 例如,下列查詢會取得目前使用中工作專案的所有修訂。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemRevisions?
  $filter=WorkItem/State eq 'Active'
  &$select=WorkItemId, Title

❌ [BLOCKED]不要在相異數據行上分組

您可以使用群組作業來減少記錄數目。 在 groupby 子句中使用相異列指示問題,且查詢會立即失敗。 如果您不小心遇到這種情況,您會收到下列錯誤訊息。

此查詢的 groupby 子句中指定的一或多個欄位不被推薦使用。

若要解決此問題,請從 groupby 子句中移除唯一欄。

❌ [BLOCKED]請勿使用 countdistinct 匯總

即使 OData 確實支援,分析仍不支援此 countdistinct 函式。 雖然我們計劃在未來新增支援,但目前尚無此功能可用。 包含此函式的查詢會傳回下列錯誤訊息。

不支援套用與匯總相異計數的查詢。

❌ 避免可能導致算術溢位的匯總

在罕見的情況下,匯總查詢可能會遇到算術溢位的問題。 例如,當您加總一些不適合加總的數值屬性時,比如工作項目實體中的StackRank。 由於數據匯總標準的 OData 延伸模組不提供將屬性轉換成不同類型的方法,因此解決此問題的唯一方法是從匯總中移除有問題的屬性。

✔️ 務必使用批次端點處理耗時查詢

您可能會因為長時間的查詢而產生問題。 特別是,當下列情況時,可能會發生問題:

  • 您可以查詢具有許多自訂欄位的專案。
  • 您的查詢是以程序設計方式建構。

OData 查詢以 HTTP GET 傳送時,目前的字元數限制為 3,000 個。 如果您超過它,您會收到「404 找不到」回應。

HTTP/1.1 404 Not Found
Content-Length: 0

若要解決此問題,請使用 OData 批次端點,如規格 OData 4.0 中所述。第 1 部分:通訊協定 - 11.7 批次要求。 批次功能主要設計用於將多個操作分組成單一HTTP請求負載,但您也可以將其作為查詢長度限制的替代方案。 藉由傳送 HTTP POST 要求,您可以傳遞任意長度的查詢,而服務會正確地解譯它。

❌ [BLOCKED]請勿使用批次端點來傳送多個查詢

我們限制批次端點的使用,不允許其處理多個請求。 單一需求仍然只能包含一個查詢。 如果您嘗試傳送數個查詢的批次,作業會失敗,並出現下列錯誤訊息。 唯一的解決方案是將查詢分割成多個要求。

分析不支持處理目前批次訊息所包含的多個作業。 Analytics 使用 OData 批次來支援 POST 請求,但要求將操作限制為單一請求。

❌ [BLOCKED]請勿使用產生超過 800 個欄的查詢

我們會限制產生超過800個數據行的查詢。 如果您在選擇查詢中返回的哪些列時不夠篩選,可能會收到下列錯誤訊息。

VS403670:指定的查詢傳回的『N』欄數超過允許的 800 欄上限。 請使用明確的$select(包括$expand內)選項來限制數據行數目。

將$select子句新增至查詢,以及$expand查詢中的作業,以避免超過此限制。

❌ 避免建立長查詢

建議您在建構長查詢時評估您採用的方法。 雖然有許多案例需要長時間查詢(例如複雜篩選條件或一長串屬性),但通常會提供次佳設計的早期指標。

當您的查詢中包含許多實體索引鍵時(例如,WorkItemId eq {id 1} or WorkItemId eq {id 2} or ...),您或許可以重寫它。 不要傳遞標識碼,而是嘗試定義一些選取相同實體集的其他準則。 有時候可能需要修改程式(例如,新增字段或標籤),但通常值得。 使用更多抽象篩選的查詢更容易維護,而且有更大的潛力可以更妥善地運作。

當您包含許多個別日期時,可能會發生另一個傾向於產生長查詢的情境(例如DateSK eq {dateSK 1} or DateSK eq {dateSK 2} or ...)。 尋找可用來建立更抽象篩選的另一個模式。 例如,下列查詢會傳回星期一建立的所有工作專案。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=CreatedOn/DayOfWeek eq 2
  &$select=WorkItemId, Title, State

✔️ 當篩選日期數據行時,請指定時區

時區 (Edm.DateTimeOffset) 會以符合 組織時區設定的位移來公開所有日期和時間資訊。 此數據既精確又易於理解。 另一個不顯眼的結果是,所有篩選條件都必須傳遞時區資訊。 如果您略過,就會收到下列錯誤訊息。

URI 中指定的查詢無效。 未指定日期時間偏移量。 使用以下兩種格式之一:YYYY-MM-ddZ 來指定午夜以後的所有內容,或使用 yyyy-MM-ddThh:mm-hh:mm(ISO 8601 標準日期與時間表示法)來指定偏移量。

若要解決此問題,請新增時區資訊。 例如,假設組織已設定為在 “(UTC-08:00) Pacific Time (US & Canada)” 時區中顯示數據,下列查詢會取得自 2020 年初以來建立的所有工作專案。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=CreatedDate ge 2020-01-01T00:00:00-08:00
  &$select=WorkItemId, Title, State

相同的解決方案適用於具有正位移的時區,但是加號字元 (+) 在 URI 中具有特殊意義,您必須正確處理。 如果您將2020-01-01T00:00:00+08:00(帶有+字元)指定為起點,您會遇到以下錯誤。

URI 中指定的查詢無效。 'CreatedDate ge 2020-01-01T0000 08:00' 中位置 31 的語法錯誤。

若要解決此問題,請將字元+取代為使用其編碼版本的形式%2B。 例如,假設組織設定為在 “(UTC+08:00) 北京、重慶、香港、烏魯木齊”時區顯示數據,下列查詢會傳回自 2020 年初以來建立的所有工作專案。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=CreatedDate ge 2020-01-01T00:00:00%2B08:00
  &$select=WorkItemId, Title, State

替代方法是使用日期代理索引鍵屬性,因為它們不會保留時區資訊。 例如,下列查詢會傳回自 2020 年初開始建立的所有工作專案,而不論組織的設定為何。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=CreatedDateSK ge 20200101
  &$select=WorkItemId, Title, State

效能指導方針

可執行動作

不要

考慮

避免

  • 避免在或子句中使用、或屬性

✔️ DO 測量實行性能指導方針的效果

如同任何效能建議,您不應該盲目實作它們。 相反地,務必擷取基準並 測量 您進行的變更所帶來的效果。 所有指導方針都是根據與具有特定需求和挑戰的分析用戶端互動而建立的。 這些建議被視為一般且可能適用於任何設計類似查詢的人。 不過,在罕見的情況下,遵循指導方針可能對效能沒有影響,甚至產生負面影響。 您確實需要測量差異,才能注意到差異。 如果發生這種情況,請在 開發人員社群 入口網站中提供意見反應。

有許多選項可用來測量效能。 最簡單的方式是直接在瀏覽器中執行兩個相同查詢的版本。 觀察在開發人員工具中所需的時間。 例如,您可以在 Microsoft Edge F12 開發人員工具中使用網路面板。 另一個選項是使用 Fiddler Web 調試程式工具擷取此資訊。

無論您的方法為何,請多次執行這兩個查詢。 例如,執行每個查詢 30 次,以擁有足夠大的範例集。 然後找出效能特性。 分析遵循多租戶架構。 因此,同時發生的其他作業可能會影響查詢的持續時間。

✔️ DO 使用匯總延伸模組

到目前為止,若要改善查詢的效能,最好是使用匯總延伸模組 - 適用於數據匯總的 OData 延伸模組。 使用聚合擴展功能,在伺服器端摘要數據,並返回比在用戶端應用相同函數所能取得的回應更小的結果。 最後,分析已針對這種類型的查詢進行優化,因此請加以使用。

如需詳細資訊,請參閱 匯總數據。

✔️ DO 在 $select 子句中指定欄位

指定您在$select子句中要的欄位。 分析是以數據行存放區索引技術為基礎所建置。 這表示數據的儲存和查詢處理都是以列為基礎。 藉由在 $select 子句中減少參考的屬性集,您可以減少必須掃描的欄位數量,並改善查詢的整體效能。

例如,下列查詢會指定工作專案的欄位。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $select=WorkItemId, Title, State

注意

Azure DevOps 支援程式自定義。 有些系統管理員會使用這項功能,並建立數百個自定義欄位。 如果您省略 $select 子句,您的查詢會傳回所有欄位,包括自定義欄位。

✔️ 請在$expand子句內的$selectexpand 選項中指定欄名

類似於 $select 子句規範,請在 $expand 子句內的 $select 擴展選項中指定屬性。 很容易忘記,但如果您省略它,回應會包含展開物件中的所有屬性。

例如,下列查詢會指定工作專案及其父項的欄位。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $select=WorkItemId, Title, State
  &$expand=Parent($select=WorkItemId, Title, State)

✔️ 當您查詢歷程記錄工作項目資料時,請在 RevisedDateSK 上定義過濾器(WorkItemRevisions 或 WorkItemSnapshot 實體集)

當您查詢歷程記錄數據時,您可能會對最近一個期間感興趣(例如 30 天、90 天)。 由於工作專案實體的實作方式,因此有一個方便的方式可讓您撰寫這類查詢以取得絕佳的效能。 每次更新工作專案時,它會建立新的修訂,並在欄位中記錄此動作 System.RevisedDate ,使其非常適合歷程記錄篩選。

在 Analytics 中,修訂日期會顯示在 RevisedDate (Edm.DateTimeOffset) 和 RevisedDateSK (Edm.Int32) 屬性中。 為了獲得最佳效能,請使用後者。 它是日期代理鍵,代表創建修訂的日期,或者為作用中且未完成的修訂提供null 的日期。 如果您想要包含之後 {startDate} 的所有日期,請將下列篩選新增至您的查詢。

RevisedDateSK eq null or RevisedDateSK gt {startDateSK}

例如,下列查詢會傳回自 2020 年初以來每天的工作項目數目。 請注意,除了在 DateSK 欄位上明顯的篩選器之外,還有另一個在 RevisedDateSK 上的篩選器。 雖然看起來可能多餘的,但它可協助查詢引擎篩選出不在範圍內的修訂,並大幅改善查詢效能。

https://analytics.dev.azure.com/{OrganizationName}/_odata/v1.0/WorkItemSnapshot?
  $apply=
    filter(DateSK gt 20200101)/
    filter(RevisedDateSK eq null or RevisedDateSK gt 20200101)/
    groupby(
      (DateValue), 
      aggregate($count as Count)
    )

注意

我們在開發 Burndown 小工具時,想出了這項建議。 一開始,我們只定義篩選條件 DateSK ,但無法讓此查詢適用於具有大型數據集的組織。 在查詢分析期間,我們注意到 DateSK 無法有效篩選修訂。 只有在我們新增了篩選器 RevisedDateSK 之後,我們才能在大規模下獲得絕佳的效能。
~ 產品小組

✔️ 請針對跨越很長一段時間的趨勢查詢使用每周或每月快照

根據預設,所有快照表都會建模為 每日快照事實 表。 如果您查詢時間範圍,則會取得每天的值。 較長的時間範圍會導致大量的記錄。 如果您不需要如此高的精確度,您可以使用每週或甚至每月的快照。

您可以使用其他篩選表示式來移除未完成指定周或月份的天數。 使用 IsLastDayOfPeriod 屬性,此屬性是針對這個案例而新增至 Analytics 的。 此屬性的類型為 Microsoft.VisualStudio.Services.Analytics.Model.Period ,可以判斷某一天是否在不同的期間完成(例如,周、月等等)。

<EnumType Name="Period" IsFlags="true">
  <Member Name="None" Value="0"/>
  <Member Name="Day" Value="1"/>
  <Member Name="WeekEndingOnSunday" Value="2"/>
  <Member Name="WeekEndingOnMonday" Value="4"/>
  <Member Name="WeekEndingOnTuesday" Value="8"/>
  <Member Name="WeekEndingOnWednesday" Value="16"/>
  <Member Name="WeekEndingOnThursday" Value="32"/>
  <Member Name="WeekEndingOnFriday" Value="64"/>
  <Member Name="WeekEndingOnSaturday" Value="128"/>
  <Member Name="Month" Value="256"/>
  <Member Name="Quarter" Value="512"/>
  <Member Name="Year" Value="1024"/>
  <Member Name="All" Value="2047"/>
</EnumType>

由於 Microsoft.VisualStudio.Services.Analytics.Model.Period 被定義為具有旗標的列舉,請使用 OData has 運算符,並為期間常值指定完整類型。

IsLastDayOfPeriod has Microsoft.VisualStudio.Services.Analytics.Model.Period'Month'

例如,下列查詢會傳回每個月最後一天所定義的工作項目計數。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItemSnapshot?
  $apply=
    filter(IsLastDayOfPeriod has Microsoft.VisualStudio.Services.Analytics.Model.Period'Month')/
    groupby(
      (DateValue), 
      aggregate($count as Count)
    )

✔️ 當依標記篩選時,請對工作專案使用 Tags 集合屬性

您可以使用TagNames屬性與contains函數來判斷工作是否已被特定標籤標記。 不過,這種方法可能會導致查詢速度緩慢,尤其是在同時檢查多個標籤時。 為了獲得最佳效能和結果,請改用 Tags 導覽屬性。

例如,下列查詢會取得所有被標記為 {tag} 的工作項目。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=Tags/any(t:t/TagName eq '{tag}')
  &$select=WorkItemId, Title, State

當您需要篩選多個標籤時,此方法也非常適用。 例如,下列查詢會傳回標記為 {tag1} 或 {tag2} 的所有工作專案。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=Tags/any(t:t/TagName eq {tag1} or t/TagName eq {tag2})
  &$select=WorkItemId, Title, State

您也可以將這些篩選條件與 「and」 運算子結合。 例如,下列查詢會取得同時以{tag1}和{tag2}標記的所有工作項目。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=Tags/any(t:t/TagName eq {tag1}) and Tags/any(t:t/TagName eq {tag2})
  &$select=WorkItemId, Title, State

✔️ 如果您想要將工作專案上的所有標籤顯示為文字,請使用 TagNames 屬性

上一節所述的導覽屬性 Tags非常適合用於篩選。 不過,當查詢傳回巢狀集合中的標籤時,使用它們會產生一些挑戰。 數據模型也包含基本 TagNames 屬性 (Edm.String),我們新增以簡化標記取用案例。 這是單一文字值,其中包含與分號 “; ” 分隔符結合的所有標記清單。 當您需要一起顯示標籤時,請使用這個屬性。 您可以將它與先前所述的標籤篩選結合。

例如,下列查詢會取得所有已標記為{tag}的工作專案。 它會傳回工作專案的標識碼、標題、狀態,以及合併標籤的文字表示。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=Tags/any(t:t/TagName eq '{tag}')
  &$select=WorkItemId, Title, State, TagNames

重要

屬性 TagNames 的長度限制為1024個字元。 它包含一組符合該限制的標籤。 如果工作專案有許多標籤或標籤過長,那麼 TagNames 可能無法包含完整的集合,應改用 Tag 導覽屬性。

❌ 請勿使用 tolower 和 toupper 函式來執行不區分大小寫的比較

如果您已與其他系統搭配使用,您可能預期會使用 tolower 或 toupper 函式來進行不區分大小寫的比較。 使用分析時,所有字串比較預設不區分大小寫,因此您不需要套用任何函式來明確處理它。

例如,下列查詢會取得以 「QUALITY」、“quality” 或這個單字的任何其他大小寫組合標記的所有工作專案。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=Tags/any(t:t/TagName eq 'quality')
  &$select=WorkItemId, Title, State, TagNames

❌ 請勿使用無界限擴充 $levels=max

OData 能夠擴充階層式結構的所有層級。 例如,工作項目追蹤中有一些實體可以應用無限制的展開。 此作業僅適用於具有少量數據的組織。 它對較大的數據集的擴展性不足。 不要使用它,如果:

  • 您正在處理大型資料集。
  • 您正在開發小工具,且無法控制小工具的安裝位置。

✔️ DO 使用伺服器驅動分頁

如果您要求的集合過大而無法在單一回應中傳送,Analytics 會套用分頁。 回應只包含部分集,以及允許擷取下一組部分項目的連結。 此策略在 OData 規格 - OData 版本 4.0 中描述。第 1 部分:通訊協定 - 伺服器驅動分頁。 藉由讓服務控制分頁,您會獲得最佳效能,因為 skiptoken 經過精心設計,以便為每個實體達到最高效能。

下一頁的連結會包含在屬性中 @odata.nextLink 。

{
  "@odata.context": "https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/$metadata#WorkItems(*)",
  "value": [
    ...
  ],
  "@odata.nextLink":"https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?$skiptoken=12345"}

注意

大部分現有的 OData 用戶端都可以自動處理伺服器驅動分頁。 例如,下列工具已使用此策略:Power BI、SQL Server Integration Services 和 Azure Data Factory。

❌ 請勿使用 $top 和 $skip 查詢選項來實現以客戶端為主導的分页

使用其他 REST API 時,您可能已使用 $top 和 $skip 查詢選項來實現用戶端驅動的分頁。 請勿將它們與分析搭配使用。 這種方法有幾個問題,效能就是其中之一。 相反地,請採用上一節所述的伺服器驅動分頁策略。

✔️ DO 使用 $top 查詢選項來限制記錄數目

只有在搭配$skip使用時,才不建議使用查詢選項$top。 如果您的報告案例中,您只需要記錄的子集(例如範例),則可以使用 $top 查詢選項。 此外,如果您需要根據某些準則來排名記錄,您應該一律搭配使用 $top$orderby ,以取得排名最上層記錄的穩定結果。

✔️ 請考慮撰寫查詢以傳回少量記錄

撰寫查詢以傳回少量記錄是最直覺的指導方針。 請務必只擷取您真正關心的數據。 您可以透過充分利用 OData 查詢語言中提供的強大篩選功能來達成此目的。

✔️ 請考慮將選取的屬性數目限制為最小值

某些專案管理員會藉由新增自定義欄位來大量自定義其程式。 在擷取寬實體上所有可用資料行時,大量客製化可能會導致效能問題(例如WorkItems)。 分析是以數據行存放區索引技術為基礎所建置。 這表示數據的存儲和查詢處理都是以列為基礎的。 因此,查詢參考的屬性越多,處理成本就越高。 務必將查詢中的屬性集限制在報告情境中你真正重要的內容之內。

✔️ 考慮篩選日期代理索引鍵屬性 (DateSK 後綴)

您有許多方式可以定義日期篩選。 您可以直接篩選日期屬性(例如 CreatedDate)、其導航頁面對應項(例如 CreatedOnDate),或其代理索引鍵表示法(例如 CreatedDate)。 最後一個選項會產生最佳效能,而且當報告需求允許時會優先使用。

例如,下列查詢會取得所有自 2020 年初以來建立的工作項目。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=CreatedDateSK ge 20200101

✔️ 考慮篩選 Surrogate 鍵的欄位

如果您想要篩選依據相關物件值的數據(例如,透過專案名稱篩選工作項目),您一律有兩個選擇。 您可以使用導覽屬性(例如 Project/ProjectName),或預先擷取 Surrogate 索引鍵 ,並直接在查詢中使用它(例如 , ProjectSK。

如果您要建置小工具,建議您使用後者選項。 當索引鍵當做查詢的一部分傳遞時,必須接觸的實體集數目會降低,而且效能會改善。

例如,下列查詢使用ProjectSK屬性來篩選WorkItems,而不是使用Project/ProjectName導覽屬性。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=ProjectSK eq {projectSK}

❌避免在$filter 或 $expand子句中使用Parent、Children 或 Revisions屬性

工作專案是整個數據模型中成本最高的實體。 它們有數個導覽屬性,可用來存取相關的工作專案:Parent、、 ChildrenRevisions。 不過,每次您在查詢中使用它們時,都預期效能會下降。 請經常質疑您是否真的需要這些屬性中的一個,並可能更新您的設計。

例如,您可以擷取更多工作專案,並使用 ParentWorkItemId 屬性在用戶端重新建構完整的階層,而不是展開 Parent。 逐案執行這類優化。

✔️ 請考慮在 VSTS.Analytics.MaxSize 標頭中傳遞喜好設定

當您執行查詢時,您不知道查詢傳回的記錄數目。 傳送另一個具有聚合的查詢,或是遵循所有後續的連結以取得整個數據集。 分析尊重 VSTS.Analytics.MaxSize 偏好設定,這可讓您在資料集超過客戶端可接受的情況下快速檢測失敗。

此選項在資料匯出情境中非常有用。 若要使用它,您必須將標頭新增 Prefer 至 HTTP 要求,並將 設定 VSTS.Analytics.MaxSize 為非負值。 值 VSTS.Analytics.MaxSize 代表您可以接受的記錄數目上限。 如果您將它設定為零,則會使用預設值 200 K。

例如,下列查詢會傳回工作項目,如果數據集小於或等於 1000 筆記錄。

GET https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems HTTP/1.1
User-Agent: {application}
Prefer: VSTS.Analytics.MaxSize=1000
OData-MaxVersion: 4.0
Accept: application/json;odata.metadata=minimal
Host: analytics.dev.azure.com/{OrganizationName}

如果數據集超過 1000 筆記錄的限制,查詢會立即失敗,並出現下列錯誤。

查詢結果包含 1,296 個數據列,超過允許的大小上限 1000。 透過套用額外過濾器減少記錄數量

如需設定頁面大小上限的詳細資訊,請參閱 ODataPreferenceHeader.MaxPageSize 屬性。

查詢樣式指導方針

✔️ 務必在匯總方法中使用 $count 虛擬屬性

某些實體會公開 Count 屬性。 當數據匯出至不同的記憶體時,它們可讓某些報告案例更容易。 不過,您不應該在 OData 查詢中的匯總中使用這些數據行。 請改用 $count 虛擬屬性。

例如,下列查詢會傳回工作項目總數。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $apply=aggregate($count as Count)

❌ 避免在 URL 區段中使用 $count 虛擬屬性

雖然 OData 標準可讓您針對實體集使用 $count 虛擬屬性(例如 _odata/v1.0/WorkItems/$count),並非所有用戶端都可以正確解譯回應。 因此,建議改用匯總。

例如,下列查詢會傳回工作項目總數。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $apply=aggregate($count as Count)

✔️ 請考慮使用參數別名來分隔查詢的變動部分

參數別名提供優雅的解決方案,可從主要查詢文字擷取動態部分,例如參數值。 您可以在評估的運算式中使用它們:

  • 基本值
  • 複雜值
  • 基本值或複雜值的集合。

如需詳細資訊,請參閱 OData 4.0 版。第 2 部分:URL 慣例 - 5.1.1.13 參數別名。 當查詢文字作為模板並可用使用者提供的值進行實例化時,參數會很有用。

例如,下列查詢會使用 @createdDateSK 參數來分隔值與篩選表達式。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=CreatedDateSK ge @createdDateSK
  &$select=WorkItemId, Title, State
  &@createdDateSK=20200101

❌ 避免在單一查詢中混合 $apply 和 $filter 子句

如果您想要將 新增 filter 至查詢,您有兩個選項。 您可以使用$filter子句或$apply=filter()組合來執行此動作。 這些選項中的每一個都適合自己使用,但將它們結合在一起可能會導致一些非預期的結果。

儘管有預期,但 OData 會清楚定義評估的順序。 此外,子 $apply 句的優先順序會優先於 $filter。 基於這個理由,您應該選擇一個或另一個,但在單一查詢中避免這兩個篩選選項。 如果自動產生查詢,這很重要。

例如,下列查詢會先依StoryPoint gt 5篩選工作專案,然後匯總結果按路徑,最後再依StoryPoints gt 2篩選結果。 使用此評估順序時,查詢一律會傳回空集。

https://analytics.dev.azure.com/{OrganizationName}/_odata/{version}/WorkItems?
  $filter=StoryPoints gt 2
  $apply=
    filter(StoryPoints gt 5)/
    groupby(
      (Area/AreaPath),
      aggregate(StoryPoints with sum as StoryPoints)
    )

✔️ 請考慮建構查詢以符合 OData 評估順序

由於在單一查詢中混合 $apply 和 filter 子句可能會導致潛在的混淆,因此建議您建構查詢子句以符合評估順序。

  1. $apply
  2. $filter
  3. $orderby
  4. $expand
  5. $select
  6. $skip
  7. $top

✔️ 請考慮檢閱元數據批注中所述的 OData 功能

當您不確定哪些 OData 功能分析支援時,您可以在元數據中查閱批注。 OASIS 開放數據通訊協定(OData)技術委員會在 TC GitHub 存放庫中維護一份可用註釋的清單。

例如,支持的篩選函式清單可在 Org.OData.Capabilities.V1.FilterFunctions 實體容器的註釋中使用。

<Annotation Term="Org.OData.Capabilities.V1.FilterFunctions">
  <Collection>
  <String>contains</String>
  <String>endswith</String>
  [...]
  </Collection>
</Annotation>

另一個有用的註釋是Org.OData.Capabilities.V1.ExpandRestrictions,它說明您無法在$expand子句中使用的導覽屬性。 例如,下列註釋說明Revisions在WorkItems實體集中無法展開。

<EntitySet Name="WorkItems" EntityType="Microsoft.VisualStudio.Services.Analytics.Model.WorkItem">
  [...]
  <Annotation Term="Org.OData.Capabilities.V1.ExpandRestrictions">
    <Record>
      <PropertyValue Property="Expandable" Bool="true"/>
      <PropertyValue Property="NonExpandableProperties">
        <Collection>
          <NavigationPropertyPath>Revisions</NavigationPropertyPath>
        </Collection>
      </PropertyValue>
    </Record>
  </Annotation>
</EntitySet>