Ho una tabella di circa 100 milioni di righe che ho intenzione di copiare per alterare, aggiungendo un indice. Non sono così preoccupato del tempo necessario per creare la nuova tabella, ma l'indice creato sarà più efficiente se modifico la tabella prima di inserire dati o inserire prima i dati e poi aggiungere l'indice?È meglio creare un indice prima di riempire una tabella con i dati o dopo che i dati sono stati posizionati?
risposta
Creazione dell'indice dopo l'inserimento dei dati è un modo più efficiente (spesso consigliato anche per rilasciare l'indice prima dell'importazione batch e dopo l'importazione per ricrearlo).
esempiosintetico (PostgreSQL 9.1, macchina lenta di sviluppo, un milione di righe):
CREATE TABLE test1(id serial, x integer);
INSERT INTO test1(id, x) SELECT x.id, x.id*100 FROM generate_series(1,1000000) AS x(id);
-- Time: 7816.561 ms
CREATE INDEX test1_x ON test1 (x);
-- Time: 4183.614 ms
Inserisci e quindi creare l'indice - circa 12 sec
CREATE TABLE test2(id serial, x integer);
CREATE INDEX test2_x ON test2 (x);
-- Time: 2.315 ms
INSERT INTO test2(id, x) SELECT x.id, x.id*100 FROM generate_series(1,1000000) AS x(id);
-- Time: 25399.460 ms
Crea indice e quindi inserire - circa 25.5 sec (più di due volte più lento)
Probabilmente è meglio creare l'indice dopo aver aggiunto le righe. Non solo sarà più veloce, ma il bilanciamento dell'albero sarà probabilmente migliore.
Modifica "bilanciamento" probabilmente non è la scelta migliore di termini qui. Nel caso di un albero b, è equilibrato per definizione. Ma ciò non significa che il b-tree abbia il layout ottimale. La distribuzione del nodo figlio all'interno dei genitori può essere irregolare (il che comporta maggiori costi negli aggiornamenti futuri) e la profondità dell'albero può risultare più profonda del necessario se il bilanciamento non viene eseguito con attenzione durante gli aggiornamenti. Se l'indice viene creato dopo l'aggiunta delle righe, è più probabile che abbia una distribuzione migliore. Inoltre, le pagine indice sul disco potrebbero presentare una minore frammentazione dopo la creazione dell'indice. A bit more information here
Non importa su questo problema perché:
- Se si aggiungono prima i dati alla tabella e dopo si aggiunge l'indice. Il tempo di generazione dell'indice sarà
O(n*log(N))
più lungo (doven
è una riga aggiunta). Poiché il tempo di gerarchia degli alberi èO(N*log(N))
, se dividi questo in dati vecchi e nuovi dati ottieniO((X+n)*log(N))
, questo può essere semplicemente convertito inO(X*log(N) + n*log(N))
e in questo formato puoi semplicemente vedere che cosa attendi. - Se si aggiunge indice e dopo aver inserito i dati. Ogni riga (hai
n
nuove righe) si allunga il tempo addizionaleO(log(N))
necessario per rigenerare la struttura dell'albero dopo aver aggiunto un nuovo elemento (colonna dell'indice dalla nuova riga, perché l'indice esiste già e la nuova riga è stata aggiunta, quindi l'indice deve essere rigenerato a struttura equilibrata, questo costoO(log(P))
doveP
è un indice di potenza [elementi nell'indice]). Hain
nuove righe e infine hain * O(log(N))
quindi il tempo di sintesi aggiuntivoO(n*log(N))
.
Non sono sicuro che sarà davvero importante per l'efficienza dell'indice, poiché in entrambi i casi si stanno inserendo nuovi dati nell'indice. Il server non saprebbe come un indice sarebbe sbilanciato fino a dopo la sua costruzione, in pratica. Sinceramente, ovviamente, fai gli inserti senza l'indice.
Gli indici creati dopo sono molto più veloci nella maggior parte dei casi. Caso in questione: 20 milioni di righe con testo completo su varchar (255) - (Nome commerciale) Indice in vigore durante l'importazione di righe: una corrispondenza contro l'assunzione di fino a 20 secondi nei casi peggiori. Rilasciare e ricreare - abbinare meno di 1 secondo ogni volta
+1, gli indici rallenteranno notevolmente un'operazione che coinvolge l'attività di inserimento di righe di 100M, quindi meglio lasciarli e ricrearli. – code4life