Linee guida per le query di OData Analytics per Azure DevOps

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

Gli sviluppatori di estensioni possono trarre vantaggio seguendo le linee guida fornite in questo articolo per progettare query OData efficienti su Analytics per Azure DevOps. Seguendo queste linee guida, assicurarsi che le query abbiano prestazioni ottimali per il tempo di esecuzione e l'utilizzo delle risorse. Le query che non rispettano queste linee guida potrebbero comportare prestazioni scarse, con tempi di attesa lunghi del report, query che superano il consumo di risorse consentite o blocchi del servizio.

Nota

Il servizio Analytics viene abilitato e supportato automaticamente nell'ambiente di produzione per tutti i Servizi DevOps di Azure. L'integrazione di Power BI e l'accesso al feed OData del servizio di analisi sono disponibili a livello generale. Ti invitiamo a usarlo e a inviare commenti e suggerimenti. I dati disponibili dipendono dalla versione. La versione supportata più recente è v2.0e la versione di anteprima più recente è v4.0-preview. Per altre informazioni, vedere Controllo delle versioni dell'API OData.

Nota

Il servizio Analytics viene installato e supportato automaticamente nell'ambiente di produzione per tutte le nuove raccolte di progetti per Azure DevOps Server 2020 e versioni successive. L'integrazione di Power BI e l'accesso al feed OData del servizio di analisi sono disponibili a livello generale. Ti invitiamo a usarlo e a inviare commenti e suggerimenti. Se è stato eseguito l'aggiornamento da Azure DevOps Server 2019, è possibile installare il servizio Analytics durante l'aggiornamento.

I dati disponibili dipendono dalla versione. La versione supportata più recente è v2.0e la versione di anteprima più recente è v4.0-preview. Per altre informazioni, vedere Controllo delle versioni dell'API OData.

Nota

Il servizio Analytics è disponibile in anteprima per Azure DevOps Server 2019. È possibile abilitarlo o installarlo per una raccolta di progetti. L'integrazione di Power BI e l'accesso al feed OData del servizio di analisi sono disponibili in anteprima. Ti invitiamo a usarlo e a inviare commenti e suggerimenti.

I dati disponibili dipendono dalla versione. La versione supportata più recente è v2.0e la versione di anteprima più recente è v4.0-preview. Per altre informazioni, vedere Controllo delle versioni dell'API OData.

Queste linee guida sono precedute dai termini DO, CONSIDER, AVOID e DON'T. Le regole restrittive applicate da Analytics contengono il prefisso [BLOCKED]. È necessario comprendere i compromessi tra soluzioni diverse. In determinate circostanze, potrebbero essere presenti requisiti per i dati che forzano l'utente a violare una o più linee guida. Tali casi dovrebbero essere rari. È consigliabile avere una ragione chiara e convincente per tali decisioni.

Suggerimento

Gli esempi illustrati in questo documento si basano su un URL di Azure DevOps Services. Usare le sostituzioni per le versioni locali.

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

Messaggi di errore e di avviso

✔️ Esaminare gli avvisi di risposta OData

Ogni query eseguita viene verificata in base a un set di regole predefinite. Le violazioni restituiscono la risposta OData seguente @vsts.warnings. Esaminare questi avvisi man mano che forniscono informazioni correnti e sensibili al contesto su come migliorare la query.

{
  "@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."
  ],
  ...
}

✔️ Esaminare i messaggi di errore OData

Le query che violano una regola di errore OData generano una risposta non riuscita con un codice di stato 400 (richiesta non valida). I messaggi associati non vengono visualizzati all'interno della @vsts.warnings proprietà . Generano invece un messaggio di errore nella message proprietà nella risposta JSON.

{
  "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."
  }
}

Restrizioni

Do's

Consider

Bloccati

Evitare

✔️ LIMITARE la query ai progetti a cui si ha accesso

Se la query è destinata ai dati di un progetto a cui non si ha accesso, la query restituisce un messaggio "Accesso al progetto negato". Per assicurarsi di avere accesso, assicurarsi che l'autorizzazione Visualizza analisi sia impostata su Consenti per tutti i progetti su cui si esegue la query. Per altre informazioni, vedere Autorizzazioni necessarie per accedere ad Analisi.

Se non si ha accesso a un progetto, viene visualizzato il messaggio seguente:

I risultati della query includono i dati in uno o più progetti per i quali non si ha accesso. Aggiungere uno o più filtri di progetti per specificare i progetti a cui si ha accesso nell'entità 'WorkItems'. Se si usano $expand o proprietà di navigazione, per tali entità è necessario un filtro di progetto.

Per risolvere questo problema, è possibile aggiungere in modo esplicito un filtro di progetto o usare l'endpoint con ambito progetto, come illustrato più avanti in questo articolo.

Ad esempio, la query seguente recupera gli elementi di lavoro appartenenti a progetti denominati {projectSK1} e {projectSK2}.

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

✔️ SPECIFICAre il filtro del progetto all'interno della $expand clausola se l'espansione potrebbe includere dati in altri progetti potenzialmente inaccessibili

Quando si espandono le proprietà di spostamento, è possibile che si faccia riferimento ai dati di altri progetti inaccessibili. Se si fa riferimento a dati inaccessibili, viene visualizzato lo stesso messaggio di errore elencato in precedenza: "I risultati della query includono i dati in uno o più progetti...". Analogamente, è possibile risolvere questo problema aggiungendo filtri di progetto espliciti per controllare i dati espansi.

È possibile farlo nella clausola regolare $filter per semplici proprietà di navigazione. Ad esempio, la query seguente richiede WorkItemLinks in modo esplicito la posizione in cui il collegamento e la destinazione sono presenti nello stesso progetto.

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)

È invece possibile spostare il filtro per $filter espandere l'opzione nella $expand clausola . Tuttavia, modifica la semantica della query. Ad esempio, la query seguente ottiene tutti i collegamenti da un determinato progetto e espande in modo condizionale la destinazione solo se esiste nello stesso progetto. Anche se valido, questo approccio potrebbe causare confusione perché potrebbe essere difficile determinare se una proprietà non è espansa perché è null o perché è stata filtrata. Usare questa soluzione solo se è effettivamente necessario questo particolare comportamento.

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)

L'opzione $filter di espansione è utile quando si usa la proprietà della raccolta di espansione, Children ad esempio nel WorkItems set di entità. Ad esempio, la query seguente restituisce tutti gli elementi di lavoro di un determinato progetto insieme a tutti i relativi elementi figlio appartenenti allo stesso progetto.

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)

Specificare il filtro se si espande una delle proprietà seguenti:

  • WorkItems set di entità: Parent, Children
  • WorkItemLinks set di entità: TargetWorkItem.

✔️ PRENDERE IN CONSIDERAZIONE l'esecuzione di query usando l'endpoint con ambito progetto

Se si è interessati ai dati di un singolo progetto, è consigliabile usare l'endpoint OData con ambito progetto (/{ProjectName}/_odata/v1.0). Evita i problemi descritti nelle due sezioni precedenti e filtra in modo implicito i dati per il progetto, il set di entità a cui si fa riferimento e tutte le proprietà di navigazione espanse.

Con questa semplificazione, le query della sezione precedente potrebbero essere riscritte nel formato seguente. Non solo il filtro nella clausola di espansione scompare, ma non è necessario il filtro per il set di entità principale.

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

Anche la query per gli elementi figlio dell'elemento di lavoro è molto più breve e più semplice.

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

È possibile applicare questa soluzione solo quando lo stato attivo è costituito dai dati di un singolo progetto. Per la creazione di report tra progetti, è necessario usare le strategie di filtro descritte nelle sezioni precedenti.

✔️ Attendere o arrestare l'operazione se la query supera i limiti di utilizzo

Se si eseguono molte query o le query richiedono l'esecuzione di molte risorse, è possibile superare i limiti del servizio e bloccarsi temporaneamente. Se si superano i limiti del servizio, arrestare l'operazione perché è probabile che la query successiva inviata non riesca con lo stesso messaggio di errore.

La richiesta è stata bloccata a causa del superamento dell'utilizzo della risorsa '{resource}' nello spazio dei nomi '{namespace}'.

Per altre informazioni sulla limitazione della frequenza, vedere Limiti di frequenza. Per informazioni su come progettare query OData efficienti, vedere Linee guida sulle prestazioni più avanti in questo articolo.

✔️ Attendere o arrestare l'operazione se la query non riesce con un timeout

Analogamente al superamento dei limiti di utilizzo, è consigliabile attendere o arrestare l'operazione se si verifica un timeout della query. Potrebbe segnalare un problema temporaneo, quindi è possibile riprovare una volta per verificare se il problema viene risolto. Tuttavia, i timeout persistenti indicano che la query è probabilmente troppo costosa da eseguire. Altri tentativi comportano solo il superamento dei limiti di utilizzo e l'utente viene bloccato.

TF400733: la richiesta è stata annullata: la richiesta ha superato il timeout della richiesta, riprovare.

I timeout indicano che una query richiede l'ottimizzazione. Per informazioni su come progettare query OData efficienti, vedere Linee guida sulle prestazioni più avanti in questo articolo.

❌ [BLOCCATO] DON'T use snapshot entities for anything other than aggregations

I set di entità snapshot con il Snapshot suffisso sono speciali perché vengono modellati come snapshot giornalieri. È possibile usarli per ottenere uno stato di entità così come erano alla fine di ogni giorno in passato. Ad esempio, se è stata eseguita WorkItemSnapshot una query e si filtra un singolo WorkItemIdoggetto , si otterrebbe un record per ogni giorno dopo la creazione dell'elemento di lavoro. Il caricamento diretto di tutti questi dati sarebbe costoso e molto probabilmente supererebbe i limiti di utilizzo e verrà bloccato. Tuttavia, le aggregazioni in queste entità sono consentite e consigliate. In effetti, i set di entità snapshot sono stati progettati tenendo presenti scenari di aggregazione.

Ad esempio, la query seguente ottiene il numero di elementi di lavoro come per data per osservare come è cresciuta nel gennaio 2020.

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

Per altre informazioni sulle aggregazioni, vedere Aggregare i dati.

✔️ Do include DateSK o DateValue column in groupby clause when you aggregate over snapshot tables

Poiché tutte le entità snapshot vengono modellate come tabelle snapshot giornaliere, è consigliabile includere sempre una delle proprietà del giorno (DateSK o DateValue) nella clausola di raggruppamento. In caso contrario, il risultato potrebbe apparire in modo errato gonfiato.

Ad esempio, se è stato raggruppato WorkItemSnapshot solo per AssignedTo proprietà e lo si aggrega con il conteggio, tutti i numeri di elementi di lavoro assegnati alle persone verrebbero moltiplicati per il numero di giorni in cui ogni assegnazione era attiva. Anche se potrebbe verificarsi una situazione in cui si tratta del risultato desiderato, questi casi sono rari.

❌ [BLOCCATO] NON usare chiavi di entità nei percorsi delle risorse per l'indirizzamento delle entità

La sintassi OData consente di accedere a una determinata entità includendo le relative chiavi direttamente nei segmenti di URL. Per altre informazioni, vedere OData versione 4.0. Parte 2: Convenzioni URL - 4.3 Indirizzamento di entità. Anche se OData consente tale indirizzamento, Analytics lo blocca. L'inclusione all'interno di una query genera l'errore seguente.

La query specificata nell'URI non è valida. Analytics non supporta la navigazione tra chiavi o proprietà, ad esempio WorkItems(Id) o WorkItem(Id)/AssignedTo. Se viene visualizzato l'errore in PowerBI, riscrivere la query per evitare una riduzione errata che causa un problema N+1.

Come hint per i messaggi di errore, alcuni strumenti client possono abusare dell'indirizzamento diretto delle entità. Anziché caricare tutti i dati in una singola richiesta, tali client potrebbero scegliere di eseguire query per ogni entità in modo indipendente. Questa procedura è sconsigliata perché può comportare un numero elevato di richieste. È invece consigliabile usare l'indirizzamento esplicito delle entità come illustrato nella sezione seguente.

✔️ DO indirizza in modo esplicito le entità con clausole di filtro

Se si desidera recuperare i dati per una singola entità, è consigliabile usare lo stesso approccio di per una raccolta di entità e definire in modo esplicito i filtri nella $filter clausola .

Ad esempio, la query seguente ottiene un singolo elemento di lavoro in base al relativo identificatore.

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

Se non si è certi delle proprietà da includere in un filtro di questo tipo, è possibile cercarla nei metadati. Vedere Costruire query OData per Analisi, componenti URL per eseguire query sui metadati. Le proprietà si trovano nell'elemento Key dell'oggetto EntityType. Ad esempio, WorkItemId e Revision sono colonne chiave per l'entità WorkItemRevision .

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

❌[BLOCCATO] NON espandere l'entità RevisionsWorkItem

Il modello di dati di Analisi non consente determinati tipi di espansioni. Uno di essi, che potrebbe essere sorprendente per alcuni, è la proprietà della Revisions raccolta sull'entità WorkItem . Se si tenta di espandere questa proprietà, viene visualizzato il messaggio di errore seguente.

La query specificata nell'URI non è valida. Impossibile utilizzare la proprietà 'Revisions' nell'opzione di query $expand.

Questa restrizione è stata messa in atto per incoraggiare tutti gli utenti a usare la soluzione consigliata, che recupera le revisioni da WorkItemRevisions come illustrato nella sezione seguente.

✔️ Usare il WorkItemRevisions set di entità per caricare tutte le revisioni per un determinato elemento di lavoro

Usare WorkItemRevisions ogni volta che si desidera recuperare la cronologia completa per un elemento di lavoro o una raccolta di elementi di lavoro.

Ad esempio, la query seguente restituisce tutte le revisioni di un elemento di lavoro con l'identificatore {id} .

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

Se si è preoccupati della cronologia completa per tutti gli elementi di lavoro che corrispondono a determinati criteri, esprimerlo usando un filtro sulla proprietà di WorkItem navigazione. Ad esempio, la query seguente ottiene tutte le revisioni di tutti gli elementi di lavoro attualmente attivi.

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

❌ [BLOCCATO] DON'T group su colonne distinte

Si usa un'operazione di raggruppamento per ridurre il numero di record. L'uso di colonne distinte nella groupby clausola indica un problema e la query ha esito negativo immediatamente. Se si verifica accidentalmente questa situazione, viene visualizzato il seguente messaggio di errore.

Non è consigliabile usare una o più colonne specificate nella clausola groupby di questa query.

Per risolvere questo problema, rimuovere la colonna distinct dalla groupby clausola .

❌[BLOCCATO] NON usare l'aggregazione countdistinct

Analytics non supporta la countdistinct funzione, anche se OData lo fa. Anche se in futuro si prevede di aggiungere supporto, non è attualmente disponibile. Una query contenente questa funzione restituisce il messaggio di errore seguente.

Le query che applicano un conteggio distinto con un'aggregazione non sono supportate.

❌ EVITARE aggregazioni che possono comportare un overflow aritmetico

In rari casi, una query di aggregazione può riscontrare problemi con l'overflow aritmetico. Ad esempio, può verificarsi quando si sommano alcune proprietà numeriche non destinate alla somma, ad esempio StackRank nelle entità dell'elemento di lavoro. Poiché lo standard OData Extension for Data Aggregation non fornisce un modo per eseguire il cast di una proprietà in un tipo diverso, l'unico modo per risolvere questo problema consiste nel rimuovere la proprietà problematica dall'aggregazione.

✔️ Usare l'endpoint batch per query lunghe

È possibile incorrere in problemi con query lunghe. In particolare, possono verificarsi problemi quando:

  • Si esegue una query su un progetto con molti campi personalizzati.
  • La query viene costruita a livello di codice.

Il limite corrente di query OData inviate con HTTP GET è di 3.000 caratteri. Se viene superato, viene restituita una risposta "404 Non trovato".

HTTP/1.1 404 Not Found
Content-Length: 0

Per risolvere questo problema, usare l'endpoint batch OData come illustrato nella specifica OData versione 4.0. Parte 1: Protocollo - 11.7 Richieste batch. La funzionalità batch è stata progettata principalmente per raggruppare più operazioni in un singolo HTTP payload di richiesta, ma è anche possibile usarla come soluzione alternativa per la limitazione della lunghezza della query. Inviando una HTTP POST richiesta, è possibile passare una query di lunghezza arbitraria e il servizio lo interpreta correttamente.

❌ [BLOCCATO] NON usare l'endpoint batch per l'invio di più query

È possibile limitare l'uso dell'endpoint batch dalla gestione di un batch di più richieste. Una singola richiesta può comunque avere una sola query. Se si tenta di inviare un batch di diverse query, l'operazione ha esito negativo con il messaggio di errore seguente. L'unica soluzione consiste nel suddividere le query in più richieste.

Analisi non supporta l'elaborazione di più operazioni contenute nel messaggio batch corrente. Analytics usa batch OData per supportare le richieste POST, ma richiede di limitare l'operazione a una singola richiesta.

❌ [BLOCCATO] NON usare query che generano più di 800 colonne

Si limitano le query che generano più di 800 colonne. Se le colonne restituite dalla query non sono sufficientemente selettive, è possibile che venga visualizzato il messaggio di errore seguente.

VS403670: la query specificata restituisce colonne 'N' superiori al limite consentito di 800 colonne. Per limitare il numero di colonne, usare $select esplicite (incluse le opzioni all'interno della $expand).

Aggiungere una clausola $select alla query e a $expand operazioni nella query per evitare di superare questo limite.

❌ EVITARE di creare query lunghe

È consigliabile valutare l'approccio ogni volta che si crea una query lunga. Anche se esistono molti scenari che richiedono una query lunga (ad esempio, filtri complessi o un lungo elenco di proprietà), in genere forniscono un indicatore iniziale di una progettazione non ottimale.

Quando la query contiene molte chiavi di entità nella query (ad esempio, WorkItemId eq {id 1} or WorkItemId eq {id 2} or ...), è possibile riscriverla. Invece di passare gli identificatori, provare a definire altri criteri che selezionano lo stesso set di entità. A volte può essere necessario modificare il processo (ad esempio, aggiungere un nuovo campo o tag), ma in genere ne vale la pena. Le query che usano filtri più astratti sono più facili da gestire e hanno un potenziale maggiore per migliorare il funzionamento.

Un altro scenario che tende a generare query lunghe si verifica quando si includono molte date singole , ad esempio DateSK eq {dateSK 1} or DateSK eq {dateSK 2} or .... Cercare un altro modello che è possibile usare per creare un filtro più astratto. Ad esempio, la query seguente restituisce tutti gli elementi di lavoro creati lunedì.

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

✔️ Specificare il fuso orario quando si filtrano in base alle colonne di data

Il fuso orario (Edm.DateTimeOffset) espone tutte le informazioni di data e ora con un offset che corrisponde alle impostazioni del fuso orario dell'organizzazione. Questi dati sono precisi e semplici da interpretare contemporaneamente. Un'altra conseguenza non eccessiva è che anche tutti i filtri devono passare le informazioni sul fuso orario. Se lo si ignora, viene visualizzato il seguente messaggio di errore.

La query specificata nell'URI non è valida. Non è stato specificato alcun offset datetime. Utilizzare uno di questi formati AAAA-MM-ggZ per specificare tutto a partire da mezzanotte o aaaa-MM-ggThh:mm-hh:mm (rappresentazione standard ISO 8601 di date e ore) per specificare l'offset.

Per risolvere questo problema, aggiungere le informazioni sul fuso orario. Ad esempio, supponendo che l'organizzazione sia configurata per visualizzare i dati in "(UTC-08:00) Pacific Time (US & Canada)", la query seguente ottiene tutti gli elementi di lavoro creati dall'inizio del 2020.

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

La stessa soluzione funziona per i fusi orari con offset positivi, ma il carattere più (+) ha un significato speciale nell'URI ed è necessario gestirlo correttamente. Se si specifica 2020-01-01T00:00:00+08:00 (con un + carattere) come punto iniziale, viene visualizzato l'errore seguente.

La query specificata nell'URI non è valida. Errore di sintassi nella posizione 31 in 'CreatedDate ge 2020-01-01T0000 08:00'.

Per risolverlo, sostituire il + carattere con la relativa versione codificata, %2B. Si supponga, ad esempio, che l'organizzazione sia configurata per visualizzare i dati in "(UTC+08:00) Pechino, Hong Kong, Urumqi" fuso orario, la query seguente restituisce tutti gli elementi di lavoro creati dall'inizio del 2020.

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

Un approccio alternativo consiste nell'usare le proprietà della chiave surrogata data perché non mantengono le informazioni sul fuso orario. Ad esempio, la query seguente restituisce tutti gli elementi di lavoro creati dall'inizio del 2020 indipendentemente dalle impostazioni dell'organizzazione.

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

Linee guida relative alle prestazioni

Do's

Non fare

Consider

Evitare

✔️ Do misurare l'effetto dell'implementazione di una linea guida sulle prestazioni

Come per le raccomandazioni sulle prestazioni, non è consigliabile implementarle in modo cieco. Acquisire invece sempre la linea di base e misurare l'effetto delle modifiche apportate. Tutte le linee guida sono state create in base alle interazioni con i client di Analytics che hanno requisiti e sfide specifici. Queste raccomandazioni sono state considerate generali e potenzialmente utili per chiunque progetti query simili. Tuttavia, in rari casi, seguire le linee guida potrebbe non avere alcun effetto o persino un effetto negativo sulle prestazioni. È necessario misurare la differenza per notarla. In questo caso, fornire commenti e suggerimenti nel portale della community per sviluppatori.

Sono disponibili molte opzioni per misurare le prestazioni. Quello più semplice consiste nell'eseguire due versioni della stessa query direttamente nel browser. Osservare il tempo necessario per gli strumenti di sviluppo. Ad esempio, è possibile usare il pannello Rete in Microsoft Edge F12 Developer Tools. Un'altra opzione consiste nell'acquisire queste informazioni usando lo strumento debugger Web fiddler.

Indipendentemente dall'approccio, eseguire entrambe le query più volte. Ad esempio, eseguire le query 30 volte per avere un set di campioni sufficientemente grande. Determinare quindi le caratteristiche delle prestazioni. Analisi segue l'architettura multi-tenant. Di conseguenza, altre operazioni che si verificano contemporaneamente possono influire sulla durata delle query.

✔️ Usare le estensioni di aggregazione

La cosa migliore da fare per migliorare le prestazioni delle query consiste nell'usare l'estensione di aggregazione - Estensione OData per l'aggregazione dei dati. Con l'estensione di aggregazione, chiedere al servizio di riepilogare il lato server dati e restituire una risposta più piccola rispetto a quella che è possibile recuperare applicando la stessa funzione lato client. Infine, Analytics è ottimizzato per questo tipo di query, quindi usarlo.

Per altre informazioni, vedere Aggregare i dati.

✔️ Specificare le colonne nella $select clausola

Specificare le colonne desiderate nella $select clausola . L'analisi si basa sulla tecnologia Columnstore Index . Ciò significa che i dati sono sia l'archiviazione che l'elaborazione delle query è basata su colonne. Riducendo il set di proprietà, si fa riferimento nella $select clausola è possibile ridurre il numero di colonne che devono essere analizzate e migliorare le prestazioni complessive della query.

Ad esempio, la query seguente specifica le colonne per gli elementi di lavoro.

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

Nota

Azure DevOps supporta la personalizzazione dei processi. Alcuni amministratori usano questa funzionalità e creano centinaia di campi personalizzati. Se si omette la clausola , la $select query restituisce tutti i campi, inclusi i campi personalizzati.

✔️ SPECIFICAre le colonne nell'opzione $select di espansione all'interno della $expand clausola

Analogamente alle linee guida della $select clausola, specificare le proprietà nell'opzione $select di espansione all'interno della $expand clausola . È facile dimenticare, ma se lo si omette, la risposta contiene tutte le proprietà dell'oggetto espanso.

Ad esempio, la query seguente specifica le colonne sia per l'elemento di lavoro che per il relativo elemento padre.

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

✔️ DEFINIRE un filtro quando RevisedDateSK si eseguono query per i dati cronologici degli elementi di lavoro (WorkItemRevisions o WorkItemSnapshot set di entità)

Quando si esegue una query per i dati cronologici, è probabile che si sia interessati al periodo più recente , ad esempio 30 giorni, 90 giorni. A causa della modalità di implementazione delle entità degli elementi di lavoro, è possibile scrivere tali query in modo da ottenere prestazioni ottimali. Ogni volta che si aggiorna un elemento di lavoro, viene creata una nuova revisione e si registra questa azione nel System.RevisedDate campo, che lo rende perfetto per i filtri della cronologia.

In Analytics la data modificata viene visualizzata nelle RevisedDate proprietà (Edm.DateTimeOffset) e RevisedDateSK (Edm.Int32). Per ottenere prestazioni ottimali, usare quest'ultimo. È la chiave surrogata della data e rappresenta la data in cui è stata creata una revisione o ha null per revisioni attive e incomplete. Se si desidera che tutte le date dall'inclusione {startDate} corrispondano, aggiungere il filtro seguente alla query.

RevisedDateSK eq null or RevisedDateSK gt {startDateSK}

Ad esempio, la query seguente restituisce il numero di elementi di lavoro per ogni giorno dall'inizio del 2020. Si noti che, a parte il filtro ovvio sulla DateSK colonna, è presente un secondo filtro su RevisedDateSK. Anche se può sembrare ridondante, consente al motore di query di filtrare le revisioni che non rientrano nell'ambito e migliora significativamente le prestazioni delle query.

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

Nota

Abbiamo creato questa raccomandazione quando stavamo lavorando sui widget Burndown. Inizialmente sono stati definiti filtri solo per DateSK ma non è stato possibile ottenere la scalabilità di questa query per le organizzazioni con set di dati di grandi dimensioni. Durante la profilatura delle query si è notato che DateSK non vengono filtrate correttamente le revisioni. Solo dopo aver aggiunto un filtro su RevisedDateSK è stato possibile ottenere prestazioni ottimali su larga scala.
~ Team prodotto

✔️ Usare snapshot settimanali o mensili per le query di tendenza che durano un lungo periodo di tempo

Per impostazione predefinita, tutte le tabelle snapshot vengono modellate come tabelle dei fatti dello snapshot giornaliero. Se si esegue una query per un intervallo di tempo, ottiene un valore per ogni giorno. Gli intervalli di tempo lunghi comportano un numero elevato di record. Se non è necessaria una precisione così elevata, è possibile usare snapshot settimanali o persino mensili.

È possibile farlo con altre espressioni di filtro per rimuovere i giorni che non terminano una determinata settimana o mese. Usare la IsLastDayOfPeriod proprietà aggiunta ad Analisi tenendo presente questo scenario. Questa proprietà è di tipo Microsoft.VisualStudio.Services.Analytics.Model.Period e può determinare se un giorno termina in periodi diversi,ad esempio settimane, mesi e così via.

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

Poiché Microsoft.VisualStudio.Services.Analytics.Model.Period è definito come enumerazione con flag, usare l'operatore OData has e specificare il tipo completo per i valori letterali punto.

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

Ad esempio, la query seguente restituisce un conteggio degli elementi di lavoro definiti nell'ultimo giorno di ogni mese.

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

✔️ Usare la Tags proprietà raccolta per gli elementi di lavoro quando si filtrano in base ai tag

È possibile usare la proprietà con la TagNamescontains funzione per determinare se un lavoro è stato contrassegnato con un tag specifico. Questo approccio, tuttavia, potrebbe comportare query lente, soprattutto quando si controllano più tag contemporaneamente. Per ottenere prestazioni e risultati ottimali, usare invece la Tags proprietà di navigazione.

Ad esempio, la query seguente ottiene tutti gli elementi di lavoro contrassegnati con un oggetto {tag}.

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

Questo approccio è utile anche quando è necessario filtrare in base a più tag. Ad esempio, la query seguente restituisce tutti gli elementi di lavoro contrassegnati con {tag1}o{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

È anche possibile combinare questi filtri con un operatore "and". Ad esempio, la query seguente ottiene tutti gli elementi di lavoro contrassegnati con e {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

✔️ Utilizzare la TagNames proprietà DO se si desidera visualizzare tutti i tag in un elemento di lavoro come testo

La proprietà di navigazione Tags, descritta nella sezione precedente, è ideale per il filtro. Tuttavia, l'uso di tali query presenta alcune problematiche perché la query restituisce tag in una raccolta nidificata. Il modello di dati contiene anche una TagNames proprietà primitiva (Edm.String), aggiunta per semplificare gli scenari di utilizzo dei tag. Si tratta di un singolo valore di testo che contiene un elenco di tutti i tag combinati con un separatore "; " punto e virgola. Utilizzare questa proprietà quando si desidera visualizzare i tag insieme. È possibile combinarlo con i filtri dei tag descritti in precedenza.

Ad esempio, la query seguente ottiene tutti gli elementi di lavoro contrassegnati con un oggetto {tag}. Restituisce l'ID dell'elemento di lavoro, il titolo, lo stato e una rappresentazione testuale dei tag combinati.

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

Importante

La proprietà TagNames ha un limite di lunghezza di 1024 caratteri. Contiene un set di tag che rientrano in tale limite. Se un elemento di lavoro ha molti tag o i tag sono molto lunghi, TagNames non contenere invece il set completo e Tag la proprietà di navigazione deve essere usata.

❌ NON usare tolower e toupper funzioni per eseguire un confronto senza distinzione tra maiuscole e minuscole

Se si lavora con altri sistemi, è possibile che si usino le tolower funzioni o toupper per il confronto senza distinzione tra maiuscole e minuscole. Con Analytics, tutti i confronti tra stringhe non fanno distinzione tra maiuscole e minuscole per impostazione predefinita, quindi non è necessario applicare alcuna funzione per gestirla in modo esplicito.

Ad esempio, la query seguente ottiene tutti gli elementi di lavoro contrassegnati con "QUALITY", "quality" o qualsiasi altra combinazione di maiuscole e minuscole di questa parola.

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

❌ NON usare l'espansione senza vincoli con $levels=max

OData offre la possibilità di espandere tutti i livelli di una struttura gerarchica. Ad esempio, il rilevamento degli elementi di lavoro include alcune entità in cui è possibile applicare un'espansione non associata. Questa operazione funziona solo per le organizzazioni con una piccola quantità di dati. Non è scalabile correttamente per set di dati di dimensioni maggiori. Non usarlo affatto se:

  • Si lavora con set di dati di grandi dimensioni.
  • Si sta sviluppando un widget e non si ha alcun controllo sulla posizione in cui viene installato il widget.

✔️ Usare il paging basato su server

Se si richiede un set troppo grande da inviare in una singola risposta, Analytics applica il paging. La risposta include solo un set parziale e un collegamento che consente di recuperare il set parziale successivo di elementi. Questa strategia è descritta nella specifica OData - OData versione 4.0. Parte 1: Protocollo - Paging basato su server. Consentendo al servizio di controllare il paging, si ottengono prestazioni ottimali perché è skiptoken stato progettato attentamente per ogni entità in modo che sia il più efficiente possibile.

Il collegamento alla pagina successiva è incluso nella @odata.nextLink proprietà .

{
  "@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"}

Nota

La maggior parte dei client OData esistenti può gestire automaticamente il paging basato su server. Ad esempio, questa strategia è già usata dagli strumenti seguenti: Power BI, SQL Server Integration Services e Azure Data Factory.

❌ NON usare $top le opzioni di query e $skip per implementare il paging basato su client

Con altre API REST, è possibile che sia stato implementato il paging basato su client con $top le opzioni di query e $skip . Non usarli con Analytics. Esistono diversi problemi con questo approccio e le prestazioni sono una di queste. Adottare invece la strategia di paging basata su server descritta nella sezione precedente.

✔️ Usare l'opzione $top di query do per limitare il numero di record

L'opzione $top di query è sconsigliata solo se usata insieme a $skip. Se nello scenario di creazione di report è necessario solo un subset di record (ad esempio, di esempio), è consigliabile usare l'opzione $top di query. Inoltre, se è necessario classificare i record in base ad alcuni criteri, è consigliabile usare $top sempre in combinazione con $orderby per ottenere risultati stabili con i record classificati più alti.

✔️ PRENDERE IN CONSIDERAZIONE la scrittura di una query per restituire un numero ridotto di record

La scrittura di una query per restituire un numero ridotto di record è la linea guida più intuitiva. Mira sempre a recuperare solo i dati di cui ti interessa davvero. È possibile ottenerlo rendendo la maggior parte delle potenti funzionalità di filtro disponibili nel linguaggio di query OData.

✔️ PRENDERE IN CONSIDERAZIONE la limitazione del numero di proprietà selezionate a un minimo

Alcuni amministratori del progetto personalizzano pesantemente i processi aggiungendo campi personalizzati. La personalizzazione intensa può causare problemi di prestazioni durante il recupero di tutte le colonne disponibili in entità wide (ad esempio, WorkItems). L'analisi si basa sulla tecnologia Columnstore Index . Ciò significa che i dati sono sia l'archiviazione che l'elaborazione delle query è basata su colonne. Quindi, più proprietà a cui fa riferimento una query, più costoso è elaborare. Mira sempre a limitare il set di proprietà nelle query a ciò che ti interessa nello scenario di creazione di report.

✔️ VALUTARE la possibilità di filtrare in base alle proprietà della chiave surrogata data (DateSK suffisso)

Esistono molti modi per definire un filtro data. È possibile filtrare direttamente la proprietà date (ad esempio, CreatedDate), la controparte di navigazione (ad esempio , ) o la relativa rappresentazione della chiave surrogata (ad esempio CreatedOnDate, CreatedDate). L'ultima opzione restituisce le prestazioni migliori ed è preferibile quando i requisiti di creazione report lo consentono.

Ad esempio, la query seguente ottiene tutti gli elementi di lavoro creati dall'inizio del 2020.

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

✔️ VALUTARE la possibilità di filtrare in base alle colonne chiave surrogate

Se si desidera filtrare i dati sul valore di un oggetto correlato ( ad esempio, filtrando un elemento di lavoro sul nome del progetto), sono sempre disponibili due opzioni. È possibile usare la proprietà di navigazione ,ad esempio , Project/ProjectNameo acquisire la chiave surrogata in primo piano e usarla direttamente nella query , ad esempio ProjectSK.

Se stai creando un widget, ti consigliamo di usare quest'ultima opzione. Quando la chiave viene passata come parte della query, il numero di set di entità che devono essere toccati viene ridotto e le prestazioni migliorano.

Ad esempio, i filtri WorkItems di query seguenti usano ProjectSK proprietà anziché Project/ProjectName proprietà di navigazione.

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

❌EVITARE di usare Parentle proprietà , Childreno Revisions nelle $filter clausole o $expand

Gli elementi di lavoro sono le entità più costose nell'intero modello di dati. Hanno diverse proprietà di navigazione che è possibile usare per accedere agli elementi di lavoro correlati: Parent, Children, Revisions. Ogni volta che le si usano all'interno di una query, tuttavia, si prevede un calo delle prestazioni. Domanda sempre se hai davvero bisogno di una di queste proprietà e potenzialmente aggiorna la progettazione.

Ad esempio, invece di espandere Parent, è possibile recuperare più elementi di lavoro e usare ParentWorkItemId la proprietà per ricostruire la gerarchia completa lato client. Eseguire tale ottimizzazione caso per caso.

✔️ VALUTARE il passaggio delle VSTS.Analytics.MaxSize preferenze nell'intestazione

Quando si esegue una query, non si conosce il numero di record restituiti dalla query. Inviare un'altra query con aggregazioni o seguire tutti i collegamenti successivi e recuperare l'intero set di dati. L'analisi rispetta le VSTS.Analytics.MaxSize preferenze, che consente di non riuscire rapidamente in tali istanze che il set di dati è maggiore di quello che il client può accettare.

Questa opzione è utile negli scenari di esportazione dei dati. Per usarla, è necessario aggiungere Prefer un'intestazione alla richiesta HTTP e impostare VSTS.Analytics.MaxSize su un valore non negativo. Il VSTS.Analytics.MaxSize valore rappresenta il numero massimo di record che è possibile accettare. Se lo si imposta su zero, viene usato un valore predefinito pari a 200 K.

Ad esempio, la query seguente restituisce elementi di lavoro se il set di dati è minore o uguale a 1000 record.

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}

Se il set di dati supera il limite di 1000 record, la query non riesce immediatamente con l'errore seguente.

Il risultato della query contiene 1.296 righe e supera le dimensioni massime consentite di 1000. Ridurre il numero di record applicando filtri aggiuntivi

Per informazioni sull'impostazione delle dimensioni massime della pagina, vedere la proprietà ODataPreferenceHeader.MaxPageSize.

Linee guida per lo stile di query

✔️ $count Usare la proprietà virtuale nei metodi di aggregazione

Alcune entità espongono Count la proprietà . Semplificano alcuni scenari di creazione di report quando i dati vengono esportati in una risorsa di archiviazione diversa. Tuttavia, non è consigliabile usare queste colonne nelle aggregazioni nelle query OData. Usare invece la $count proprietà virtuale.

Ad esempio, la query seguente restituisce il numero totale di elementi di lavoro.

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

❌ EVITARE di usare $count la proprietà virtuale nel segmento URL

Anche se lo standard OData consente di usare $count la proprietà virtuale per i set di entità (ad esempio, _odata/v1.0/WorkItems/$count), non tutti i client possono interpretare correttamente la risposta. È quindi consigliabile usare le aggregazioni.

Ad esempio, la query seguente restituisce il numero totale di elementi di lavoro.

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

✔️ PRENDERE IN CONSIDERAZIONE l'uso di alias di parametri per separare parti volatili della query

Gli alias dei parametri forniscono una soluzione elegante per estrarre parti volatili come i valori dei parametri dal testo della query principale. È possibile usarli nelle espressioni che valutano:

  • Valore primitivo
  • Valore complesso
  • Raccolta di valori primitivi o complessi.

Per altre informazioni, vedere OData versione 4.0. Parte 2: Convenzioni URL - Alias dei parametri 5.1.1.13. I parametri sono utili quando il testo della query viene usato come modello di cui è possibile creare un'istanza con i valori forniti dall'utente.

Ad esempio, la query seguente usa il @createdDateSK parametro per separare il valore dall'espressione di filtro.

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

❌ EVITARE la combinazione $apply di clausole e $filter in una singola query

Se si vuole aggiungere filter alla query, sono disponibili due opzioni. È possibile eseguire questa operazione con la $filter clausola o la $apply=filter() combinazione . Ognuna di queste opzioni funziona in modo ottimale da solo, ma combinandole insieme potrebbe portare ad alcuni risultati imprevisti.

Nonostante le aspettative, OData definisce chiaramente un ordine della valutazione. Inoltre, la clausola ha priorità $apply su $filter. Per questo motivo, è consigliabile scegliere una o un'altra, ma evitare queste due opzioni di filtro in una singola query. È importante se le query vengono generate automaticamente.

Ad esempio, la query seguente filtra prima gli elementi di lavoro in StoryPoint gt 5base a , aggrega i risultati in base al percorso e infine filtra il risultato in base StoryPoints gt 2a . Con questo ordine di valutazione, la query restituisce sempre un set vuoto.

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

✔️ PRENDERE IN CONSIDERAZIONE la strutturazione della query in modo che corrisponda all'ordine di valutazione OData

Poiché la combinazione $apply di clausole e filter in una singola query può causare confusione, è consigliabile strutturare le clausole di query in modo che corrispondano all'ordine di valutazione.

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

✔️ VALUTARE la possibilità di esaminare le funzionalità OData descritte nelle annotazioni dei metadati

Quando non si è certi delle funzionalità di OData supportate da Analytics, è possibile cercare le annotazioni nei metadati. Il comitato tecnico OASIS Open Data Protocol (OData) in un repository GitHub TC gestisce un elenco delle annotazioni disponibili.

Ad esempio, l'elenco delle funzioni di filtro supportate è disponibile nell'annotazione Org.OData.Capabilities.V1.FilterFunctions nel contenitore di entità.

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

Un'altra annotazione utile è Org.OData.Capabilities.V1.ExpandRestrictions, che spiega quali proprietà di navigazione non è possibile usare nella $expand clausola . Ad esempio, l'annotazione seguente spiega che Revisions nel WorkItems set di entità non può essere espanso.

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