dilluns, 29 de març del 2010

Emulant SEQUENCE d'Oracle a MySQL

Oracle te un component força interessant per a la gestió de comptadors. És l'objecte SEQUENCE.

Per obtenir el següent valor de la seqüència executarem
SELECT nom_sequencia.nextval FROM DUAL;

A MySQL podem muntar un workarround per a emular aquesta característica d'Oracle creant una taula i dues funcions pròpies.

Creem una taula anomenada ubqSequencia on el nom de la seqüencia és clau primaria:
CREATE TABLE `ubqSequencia` (
`sqId` varchar(64) NOT NULL COMMENT 'Nom de la seqüència',
`sqCnt` bigint(20) UNSIGNED NOT NULL COMMENT 'Comptador de la seqüència',
`sqInc` int(11) NOT NULL default '1' COMMENT 'Increment per omissió de la seqüència',
`sqObs` longtext COMMENT 'Observacions',
PRIMARY KEY (`sqId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Comptadors emulem create sequence a Oracle'


Creem una funció anomenada ubqSequenciaNextVal que li passem el nom de la seqüència i ens retorna el comptador un cop incrementat. És l'equivalent a la pseudo columna NEXTVAL d'Oracle per a objectes SEQUENCE.
DELIMITER $$

DROP FUNCTION IF EXISTS `ubqSequenciaNextVal`$$
CREATE FUNCTION `ubqSequenciaNextVal`(psqId CHAR(64)) RETURNS bigint(20)
BEGIN

insert into ubqSequencia (sqId, sqCnt, sqInc) values(psqId,1,1)
on duplicate key update sqCnt = sqCnt + sqInc;

RETURN (select sqCnt from ubqSequencia where sqId = psqId);

END$$

DELIMITER ;


Aquesta funció inicialitza sempre la seqüència que em passat com a paràmetre. En cas de que salti la clau duplicada, augmenta el comptador amb l'increment establert a la mateixa taula pel mateix comptador, per omissió +1.

I la funció ubqSequenciaCurrVal que retorna el valor actual del comptador. L'equivalent a la pseudo columna CURRVAL d'Oracle pels objectes SEQUENCE.
DELIMITER $$

DROP FUNCTION IF EXISTS `ubqSequenciaCurrVal`$$
CREATE FUNCTION `ubqSequenciaCurrVal`(psqId CHAR(64)) RETURNS bigint(20)
BEGIN

RETURN (select sqCnt from ubqSequencia where sqId = psqId);

END$$

DELIMITER ;


Un dels aspectes positius de tenir els comptadors a nivell de base de dades i no per lògica de programes, és que podem actualitzar els comptadors en MySQL des d'instruccions massives. Per exemple:


update PROVA set nouComptador = ubqSequenciaNextVal('XXYYZZ');


Actualitzant el camp nouComptador de tots els registres de la taula PROVA amb la seqüència XXYYZZ. Les proves realitzades han consumit 0.0946 segons en fer la seqüència de 414 registres en un update massiu.

Certifiquem que el comptador ha quedat actualitzat

mysql> select ubqSequenciaCurrVal('XXYYZZ');
+-------------------------------+
| ubqSequenciaCurrVal('XXYYZZ') |
+-------------------------------+
| 414 |
+-------------------------------+
1 row in set (0.00 sec)


I mostrem com afegim un

mysql> select ubqSequenciaNextVal('XXYYZZ');
+-------------------------------+
| ubqSequenciaNextVal('XXYYZZ') |
+-------------------------------+
| 415 |
+-------------------------------+