Domanda

Ho diverse tabelle i cui unici dati univoci sono una colonna uniqueidentifier (a Guid).Poiché le guide non sono sequenziali (e sono generate lato client, quindi non posso utilizzare newsequentialid()), ho creato un indice non primario e non in cluster su questo campo ID anziché fornire alle tabelle un indice primario in cluster chiave.

Mi chiedo quali siano le implicazioni sulle prestazioni per questo approccio.Ho visto alcune persone suggerire che le tabelle dovrebbero avere un int autoincrementante ("identità") come chiave primaria in cluster anche se non ha alcun significato, poiché significa che il motore di database stesso può utilizzare quel valore per rapidamente cercare una riga invece di dover utilizzare un segnalibro.

Il mio database viene replicato tramite unione su una serie di server, quindi ho evitato le colonne Identity Int poiché sono un po' complicate da inserire correttamente nella replica.

Quali sono i tuoi pensieri?Le tabelle dovrebbero avere chiavi primarie?Oppure va bene non avere indici cluster se non ci sono colonne sensate da indicizzare in questo modo?

È stato utile?

Soluzione

Quando hai a che fare con gli indici, devi determinare per cosa verrà utilizzata la tua tabella.Se stai inserendo principalmente 1000 righe al secondo e non esegui alcuna query, un indice cluster è un problema per le prestazioni.Se esegui 1000 query al secondo, la mancanza di un indice porterà a prestazioni pessime.La cosa migliore da fare quando si tenta di ottimizzare query/indici è utilizzare Query Plan Analyser e SQL Profiler in SQL Server.Questo ti mostrerà dove ti imbatti in costose scansioni di tabelle o altri blocchi delle prestazioni.

Per quanto riguarda l'argomento GUID vs ID, puoi trovare persone online che giurano su entrambi.Mi è sempre stato insegnato a utilizzare i GUID a meno che non abbia una buona ragione per non farlo.Jeff ha un buon post che parla dei motivi per l'utilizzo dei GUID: https://blog.codinghorror.com/primary-keys-ids-versus-guids/.

Come per quasi tutto ciò che riguarda lo sviluppo, se stai cercando di migliorare le prestazioni non esiste un'unica risposta giusta.Dipende davvero da cosa stai cercando di realizzare e da come stai implementando la soluzione.L'unica vera risposta è testare, testare e testare ancora rispetto ai parametri prestazionali per assicurarti di raggiungere i tuoi obiettivi.

Modifica] @Matt, dopo aver fatto ulteriori ricerche sul dibattito GUID/ID mi sono imbattuto in questo post.Come ho detto prima, non esiste una vera risposta giusta o sbagliata.Dipende dalle tue specifiche esigenze di implementazione.Ma questi sono alcuni motivi abbastanza validi per utilizzare i GUID come chiave primaria:

Ad esempio, esiste un problema noto come "hotspot", in cui alcune pagine di dati in una tabella sono soggette a un conflitto valutario relativamente elevato.Fondamentalmente, ciò che accade è che la maggior parte del traffico su una tabella (e quindi i blocchi a livello di pagina) avviene in una piccola area della tabella, verso la fine.I nuovi record andranno sempre a questo hotspot, perché IDENTITY è un generatore di numeri sequenziali.Questi inserti sono problematici perché richiedono il blocco della pagina esclusivo sulla pagina a cui vengono aggiunti (l'hotspot).Ciò serializza efficacemente tutti gli inserti su una tabella grazie al meccanismo di blocco della pagina.NewID() invece non soffre di hotspot.I valori generati utilizzando la funzione NewID() sono sequenziali solo per brevi sequenze di inserimenti (dove la funzione viene chiamata molto rapidamente, come durante un inserimento su più righe), il che fa sì che le righe inserite si diffondano casualmente nelle pagine di dati della tabella di tutto alla fine, eliminando così un hotspot dagli inserti.

Inoltre, poiché gli inserti sono distribuiti in modo casuale, la possibilità di suddivisioni delle pagine è notevolmente ridotta.Anche se una pagina divisa qua e là non è poi così male, gli effetti si sommano rapidamente.Con IDENTITY, il fattore di riempimento della pagina è piuttosto inutile come meccanismo di ottimizzazione e potrebbe anche essere impostato al 100%: le righe non verranno mai inserite in nessuna pagina tranne l'ultima.Con NewID(), puoi effettivamente utilizzare Fill Factor come strumento di ottimizzazione delle prestazioni.È possibile impostare il fattore di riempimento su un livello che si avvicina alla crescita del volume stimata tra le ricostruzioni dell'indice e quindi pianificare le ricostruzioni durante le ore non di punta utilizzando il reindicizzazione dbcc.Ciò ritarda effettivamente i risultati positivi in ​​termini di prestazioni delle divisioni di pagina fino alle ore non di punta.

Se anche tu pensare potrebbe essere necessario abilitare la replica per la tabella in questione, quindi potresti anche rendere il PK un identificatore univoco e contrassegnare il campo guid come ROWGUIDCOL.La replica richiederà un campo GUID con valore univoco con questo attributo e ne aggiungerà uno se non ne esiste nessuno.Se esiste un campo adatto, utilizzerà semplicemente quello presente.

Un altro enorme vantaggio derivante dall'utilizzo dei GUID per i PK è il fatto che il valore è effettivamente garantito univoco, non solo tra tutti i valori generati da Questo server, ma tutti i valori generati da Tutto computer, che si tratti del tuo server DB, server Web, server app o macchina client.Praticamente ogni linguaggio moderno ha ora la capacità di generare una GUID valida: in .NET puoi utilizzare System.Guid.NewGuid.Questo è MOLTO utile quando si ha a che fare con i set di dati master-detail memorizzati nella cache in particolare.Non è necessario utilizzare folli schemi di codifica temporanei solo per collegare insieme i record prima che vengano impegnati.È sufficiente recuperare un nuovo Guid perfettamente valido dal sistema operativo per il valore della chiave permanente di ogni nuovo record al momento della creazione del record.

http://forums.asp.net/t/264350.aspx

Altri suggerimenti

La chiave primaria ha tre scopi:

  • indica che le colonne devono essere univoche
  • indica che le colonne devono essere diverse da null
  • documenta l'intenzione che questo sia l'identificatore univoco della riga

I primi due possono essere specificati in molti modi, come hai già fatto.

Il terzo motivo è buono:

  • per gli umani, in modo che possano facilmente vedere le tue intenzioni
  • per il computer, quindi un programma che potrebbe confrontare o elaborare in altro modo la tabella può interrogare il database per la chiave primaria della tabella.

Una chiave primaria non deve essere un campo numerico a incremento automatico, quindi direi che è una buona idea specificare la colonna guid come chiave primaria.

Mi intrometto subito, perché Matt mi ha stuzzicato un po'.

È necessario comprendere che, sebbene un indice cluster venga inserito nella chiave primaria di una tabella per impostazione predefinita, i due concetti sono separati e devono essere considerati separatamente.Un CIX indica il modo in cui i dati vengono archiviati e a cui fanno riferimento gli NCIX, mentre il PK fornisce un'unicità per ogni riga per soddisfare i requisiti LOGICI di una tabella.

Una tabella senza CIX è solo un Heap.Una tabella senza PK è spesso considerata "non una tabella".È meglio comprendere separatamente i concetti PK e CIX in modo da poter prendere decisioni sensate nella progettazione del database.

rapinare

Nessuno ha risposto alla domanda vera e propria:quali sono i vantaggi/svantaggi di una tabella SENZA PK NÉ un indice CLUSTERED.A mio parere, se ottimizzi per inserimenti più veloci (in particolare inserti di massa incrementali, ad es.quando si caricano in massa i dati in una tabella non vuota), tale tabella:senza indice cluster, senza vincoli, senza chiavi esterne, senza valori predefiniti e senza chiave primaria, in un database con modello di recupero semplice, è il migliore.Ora, se desideri eseguire una query su questa tabella (invece di scansionarla nella sua interezza), potresti voler aggiungere indici non univoci non cluster secondo necessità, ma mantenerli al minimo.

Anch'io ho sempre sentito che avere un int con incremento automatico è positivo per le prestazioni anche se non lo usi effettivamente.

Non è necessario che una chiave primaria sia un campo ad incremento automatico, in molti casi ciò significa semplicemente che stai complicando la struttura della tabella.

Invece, una chiave primaria dovrebbe essere la raccolta minima di attributi (si noti che la maggior parte dei DBMS consentirà una chiave primaria composita) che identifica in modo univoco una tupla.

In termini tecnici, dovrebbe essere il campo da cui ogni altro campo nella tupla dipende in modo completamente funzionale.(In caso contrario potrebbe essere necessario normalizzarlo).

In pratica, i problemi di prestazioni possono significare che si uniscono tabelle e si utilizza un campo incrementale, ma mi sembra di ricordare qualcosa sull'ottimizzazione prematura che è dannosa...

Dal momento che stai eseguendo la replica, le tue identità corrette sono qualcosa da cui evitare.Vorrei rendere il tuo GUID una chiave primaria ma non in cluster poiché non puoi utilizzare newsequentialid.Mi sembra la soluzione migliore.Se non lo rendi un PK ma ci inserisci un indice univoco, prima o poi ciò potrebbe far sì che le persone che mantengono il sistema non comprendano correttamente le relazioni FK introducendo correttamente i bug.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top