giovedì 2 aprile 2009

MySQL: Generare una chiave primaria per una tabella

Oggi ho avuto la necessità di generare una chiave primaria per una tabella. Siccome non ho molto in simpatia l'uso degli autoincrement ho deciso di costruirla sulla base di un campo varchar(30).

Una delle problematiche è che in una fase di insert massivo (il sistema riesce ad inserire alcune migliaia di record in un secondo) la generazione di questa stringa non è stata semplicissima.
Vediamo comunque le strategie usate partendo dal risultato finale.
SET @numero = 1;

SELECT CONCAT('DVBH',DATE_FORMAT(NOW(),'%Y%m%d%H%i%s'),LPAD(FLOOR(1 + RAND() * 999999),7,0),LPAD(@numero := @numero + 1,5,0)) AS RecordId
Leggendo così a primo colpo può quasi spaventare, ma vediamola passo passo.
La Set iniziale servirà più avanti e per ora evito di trattarla.
Innanzi tutto per ottenere una stringa avremo bisogno ci concatenare gli elementi che useremo per andare a formare la stringa.
SELECT CONCAT('DVBH',DATE_FORMAT(NOW(),'%Y%m%d%H%i%s'),LPAD(FLOOR(1 + RAND() * 999999),7,0),LPAD(@numero := @numero + 1,5,0)) AS RecordId
Come primo elemento aggiungiamo un prefisso (in questo caso di 4 lettere) che ci identifica la tabella o qualsiasi altra cosa vi possa venire in mente.
SELECT CONCAT('DVBH',DATE_FORMAT(NOW(),'%Y%m%d%H%i%s'),LPAD(FLOOR(1 + RAND() * 999999),7,0),LPAD(@numero := @numero + 1,5,0)) AS RecordId
Per la seconda parte utilizziamo la data attuale con precisione al secondo in tale maniera ogni volta che creeremo la chiave primaria si già diversa in dipendenza del tempo.
SELECT CONCAT('DVBH',DATE_FORMAT(NOW(),'%Y%m%d%H%i%s'),LPAD(FLOOR(1 + RAND() * 999999),7,0),LPAD(@numero := @numero + 1,5,0)) AS RecordId
A questo punto siccome in un secondo possono esserci anche migliaia di inserimenti che manderebbero in violazione di chiave la nostra operazione aggiungiamo il terzo e quarto elemento. Il terzo sarò un numero randomico generato come già spiegato in un latro post secondo una formula matematica.
SELECT CONCAT('DVBH',DATE_FORMAT(NOW(),'%Y%m%d%H%i%s'),LPAD(FLOOR(1 + RAND() * 999999),7,0),LPAD(@numero := @numero + 1,5,0)) AS RecordId
Ultima parte un numero sequenziale, che io nel caso gli ho passato da una variabile @numero, ma che si può tranquillamente immagazzinare in una tabella e richiamare a piacere, aumentando il suo valore ad ogni passaggio.
SELECT CONCAT('DVBH',DATE_FORMAT(NOW(),'%Y%m%d%H%i%s'),LPAD(FLOOR(1 + RAND() * 999999),7,0),LPAD(@numero := @numero + 1,5,0)) AS RecordId
Il risultato che si ottiene è qualcosa come questo:
DVBH20090402133508062740800002
Ecco fatto!

Wsc

1 commento:

fuliggians ha detto...

sarò costretto a darti più cose da fare!!! Ma ti sembra il caso di non usare l'autoincrement!!! :-)