Azure DevOps 的 OData Analytics 查詢指導方針

Azure DevOps Services |Azure DevOps Server 2022 - Azure DevOps Server 2019

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

注意

所有 Azure DevOps Services 的生產環境中都會自動啟用及支援 Analytics 服務。 Power BI 整合 及存取 Analytics Service 的 OData 摘要 已正式推出。 我們鼓勵您使用它,並提供意見反應給我們。 可用的數據與版本相關。 最新支援的版本是 v2.0,而最新的預覽版本是 v4.0-preview。 如需詳細資訊,請參閱 OData API 版本控制

注意

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

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

注意

Azure DevOps Server 2019 的 Analytics 服務處於預覽狀態。 您可以 啟用或安裝 專案集合。 Power BI 整合 和分析 服務的 OData 摘要 存取處於預覽狀態。 我們鼓勵您使用它,並提供意見反應給我們。

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

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

提示

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

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

錯誤和警告訊息

✔️ DO 檢閱 OData 回應警告

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

{
  "@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's

Consider

已封鎖

避免

✔️ 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)

當您 $filter 使用 expand 集合屬性,例如 ChildrenWorkItems 實體集中時,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 實體集: ParentChildren
  • 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 當您匯總快照集數據表時,請在 子句中包含 groupbyDateValue 數據行

由於所有快照集實體都會模型化為 每日快照集數據表,因此您應該一律在 grouping 子句中包含其中一個日屬性 (DateSKDateValue)。 否則,結果可能會不正確地膨脹。

例如,如果您只依 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 元件以查詢元數據。 屬性位於 Key 的元素中 EntityType。 例如, WorkItemIdRevision 是實體的 WorkItemRevision 索引鍵數據行。

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

❌[BLOCKED]不要擴充RevisionsWorkItem實體

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

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 延伸模組不提供將屬性轉換成不同類型的方法,因此解決此問題的唯一方法是從匯總中移除有問題的屬性。

✔️ 請對長時間查詢使用批次端點

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

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

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

HTTP/1.1 404 Not Found
Content-Length: 0

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

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

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

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

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

我們會限制產生超過800個數據行的查詢。 如果您沒有足夠的選擇性,查詢傳回的數據行可能會收到下列錯誤訊息。

VS403670:指定的查詢會傳回大於 800 個數據行允許限制的 『N』 資料行。 請使用明確的$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's

不要

Consider

避免

✔️ 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 子句,您的查詢會傳回所有欄位,包括自定義欄位。

✔️ DO 在 子句內的 expand 選項中$expand指定數據行$select

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

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

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

✔️ 當您查詢歷程記錄工作項目資料時,請定義篩選 RevisedDateSK 條件(WorkItemRevisionsWorkItemSnapshot 實體集)

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

在 Analytics 中,修訂日期會顯示在 RevisedDateEdm.DateTimeOffset) 和 RevisedDateSKEdm.Int32) 屬性中。 為了獲得最佳效能,請使用後者。 它是 date Surrogate 索引鍵 ,它代表建立修訂的日期,或針對作用中、不完整的修訂而擁有 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 集合屬性

您可以使用 屬性搭配 函TagNamescontains式來判斷工作是否已以特定標記標記。 不過,這種方法可能會導致查詢速度緩慢,尤其是在同時檢查多個標籤時。 為了獲得最佳效能和結果,請改用 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 導覽屬性。

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

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

例如,下列查詢會取得以 「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 時,您可能已使用 和 $skip 查詢選項來實作用戶端驅動分頁$top。 請勿將它們與分析搭配使用。 這種方法有幾個問題,效能就是其中之一。 相反地,請採用上一節所述的伺服器驅動分頁策略。

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

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

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

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

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

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

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

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

例如,下列查詢會取得自 2020 年初開始建立的所有工作專案。

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

✔️ 考慮篩選 Surrogate 索引鍵數據行

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

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

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

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

❌避免在 或 子句中使用 Parent$filterChildrenRevisions 屬性$expand

工作專案是整個數據模型中成本最高的實體。 它們有數個導覽屬性,可用來存取相關的工作專案: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 至查詢,您有兩個選項。 您可以使用 子句或$apply=filter()組合來執行此動作$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 評估順序

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

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

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

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

例如,支持的篩選函式清單可在 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 導覽屬性。 例如,下列註釋說明RevisionsWorkItems無法在實體集中展開。

<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>