5

Nella mia attuale applicazione Rails, sto risolvendo i conflitti di programmazione ordinando i modelli dal campo "created_at". Tuttavia, mi sono reso conto che quando si inseriscono più modelli da un modulo che consente questo, tutti i tempi di created_at sono esattamente gli stessi!Si può fare affidamento sulla chiave primaria auto-incrementante nel proprio database?

Questa è più una questione di migliori pratiche di programmazione: la tua applicazione può fare affidamento sulla colonna ID del tuo database per incrementare sempre di più ogni INSERT per ottenere il loro ordine di creazione? Per dirla in altro modo, posso ordinare un gruppo di righe che estraggo dal mio database dalla loro colonna ID e mi assicuro che si tratta di un ordinamento accurato basato sull'ordine di creazione? E questa è una buona pratica nella mia applicazione?

risposta

1

Dipende dal fornitore del database.

MySQL Credo assolutamente ordini le chiavi di incremento automatico. SQL Server Non so per certo che lo faccia o no ma credo che lo faccia.

Dove si incontrano problemi con database che non supportano questa funzionalità, in particolare Oracle che utilizza sequenze, che sono approssimativamente ma non assolutamente ordinate.

Un'alternativa potrebbe essere quella di andare per il tempo creato e quindi l'ID.

+0

Mi piace l'idea della ridondanza, l'ordinamento di uno e l'utilizzo dell'ID per un ordinamento secondario. . . Grazie! – BushyMark

+0

Le sequenze Oracle sono ordinate per installazioni non RAC, che costituiscono la stragrande maggioranza di esse. –

2

I numeri di identificazione generati saranno unici. Indipendentemente dal fatto che si utilizzino le sequenze, come in PostgreSQL e Oracle o se si utilizza un altro meccanismo come l'auto-incremento di MySQL.

Tuttavia, le sequenze vengono acquisite più spesso in gruppi di, ad esempio 20 numeri. Quindi con PostgreSQL non è possibile determinare quale campo è stato inserito per primo. Potrebbero persino esserci degli spazi nei record dei record inseriti.

Pertanto, non utilizzare un campo ID generato per un'attività come quella per non fare affidamento sui dettagli di implementazione del database.

Generazione di un creato o aggiornato campo durante l'esecuzione del comando è molto meglio di ordinamento per creazione-, o dell'aggiornamento in seguito. Per esempio:

INSERT INTO A (data, created) VALUES (smething, DATE()) 
UPDATE A SET data=something, updated=DATE() 
0

Credo che la risposta alla tua domanda è sì ... se leggo tra le righe, credo che si teme che il sistema può riutilizzare i numeri di identificazione che sono 'scomparsi' in la sequenza, e quindi se tu avessi usato 1,2,3,5,6,7 come numeri ID, in tutte le implementazioni che conosco, il prossimo numero ID sarà sempre 8 (o forse più alto), ma io non so di qualsiasi DB che proverebbe a capire che manca l'ID n. 4, quindi cerca di riutilizzare quel numero ID.

Sebbene io abbia maggior dimestichezza con SQL Server, non so perché un fornitore che tenta di colmare le lacune di una sequenza - pensa al sovraccarico di tenere quella lista di ID inutilizzati, invece di tenere sempre traccia di dell'ultimo numero I utilizzato e aggiungendo 1.

Direi che si può tranquillamente contare sul prossimo numero ID assegnato sempre più alto dell'ultimo - non solo unico.

0

Sì, l'ID sarà univoco e no, non è possibile e non si deve fare affidamento su di esso per l'ordinamento: è lì per garantire l'unicità della riga solo. L'approccio migliore è, come indicato da emktas, per utilizzare un campo separato "aggiornato" o "creato" solo per questa informazione.

Per impostare l'ora di creazione, si può semplicemente utilizzare un valore predefinito come questo

CREATE TABLE foo (
    id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL; 
    created TIMESTAMP NOT NULL DEFAULT NOW(); 
    updated TIMESTAMP; 
    PRIMARY KEY(id); 
) engine=InnoDB; ## whatever :P 

Ora, che si occupa di ora di creazione. con il tempo di aggiornamento vorrei suggerire un UPDATE grilletto dopo come questo (naturalmente è possibile farlo in una query separata, ma il grilletto, a mio parere, è una soluzione migliore - più trasparente):

DELIMITER $$ 
CREATE TRIGGER foo_a_upd AFTER UPDATE ON foo 
FOR EACH ROW BEGIN 
    SET NEW.updated = NOW(); 
END; 
$$ 
DELIMITER ; 

E questo dovrebbe farlo

MODIFICA: Guai a me. Insolitamente non ho specificato, che questo è per mysql, potrebbero esserci alcune differenze nei nomi delle funzioni (vale a dire, 'ORA') e altri sottili itty-bitty.

+1

Stai ignorando ciò che l'OP ha detto: ha già un campo created_at e che è lo stesso quando più elementi vengono inseriti contemporaneamente, da qui la sua domanda. – cletus

+0

Sembrerebbe, infatti, che il mio modo di pensare, che devia selvaggiamente com'era, si sia spostato su una pista laterale. Scusate. Sei, ovviamente, giusto. L'ordinamento prima per created_at e poi per id è, probabilmente la soluzione più semplice (anche se probabilmente non garantisce l'ordine corretto, garantisce solo che le righe con gli stessi valori created_at verranno restituite nello stesso ordine ciascuna tempo). – shylent

0

Un avvertimento alla risposta di EJB:

SQL non fornisce alcuna garanzia di ordinare se non si specifica un ordine per colonna. Per esempio. se si eliminano alcune righe iniziali, quindi si inseriscono 'em, i nuovi potrebbero finire nello stesso posto nel db che i vecchi hanno fatto (anche se con nuovi ID), e questo è ciò che può usare come ordinamento predefinito.

FWIW, in genere utilizzo l'ordine per ID come una versione effettiva dell'ordine di created_at. È più economico in quanto non richiede l'aggiunta di un indice a un campo datetime (che è più grande e quindi più lento di un indice di chiave primaria intero semplice), garantito per essere diverso, e non mi interessa se alcune righe che erano aggiunto all'incirca alla stessa ora in ordine leggermente diverso.

0

Questo è probabilmente il motore DB dipendente. Vorrei verificare come il tuo DB implementa le sequenze e se non ci sono problemi documentati allora deciderei di affidarmi all'ID.

E.g. Postgresql sequence è OK a meno che non si giochi con i parametri della cache di sequenza.

Esiste la possibilità che un altro programmatore crei o copi manualmente i record da DB diversi con una colonna ID errata. Tuttavia vorrei semplificare il problema. Non preoccuparti dei casi a bassa probabilità in cui qualcuno distruggerà manualmente l'integrità dei dati. Non puoi proteggere contro tutto.

Il mio consiglio è di fare affidamento su ID generato in sequenza e spostare il progetto in avanti.

0

In teoria si il numero di identificazione più alto è l'ultimo creato. Ricorda però che i database hanno la capacità di disattivare temporaneamente l'inserto del valore generato automaticamente, inserire alcuni record manaully e quindi riaccenderlo. Questi inserti non sono generalmente utilizzati su un sistema di produzione, ma possono verificarsi occasionalmente quando si sposta una grande porzione di dati da un altro sistema.