Domanda

Stiamo usando MySQL con il motore di archiviazione InnoDB e le transazioni e abbiamo riscontrato un problema: abbiamo bisogno di un modo carino per emulare le SEQUENZE di Oracle in MySQL. I requisiti sono:  - supporto per la concorrenza  - sicurezza delle transazioni  - prestazioni massime (ovvero riduzione di blocchi e deadlock)

Non ci interessa se alcuni dei valori non verranno utilizzati, vale a dire che le lacune in sequenza sono ok. Esiste un modo semplice per archiviarlo creando una tabella InnoDB separata con un contatore, tuttavia ciò significa che prenderà parte alla transazione e introdurrà blocchi e attese. Sto pensando di provare una tabella MyISAM con blocchi manuali, altre idee o buone pratiche?

È stato utile?

Soluzione

Se l'incremento automatico non è abbastanza buono per le tue esigenze, puoi creare un meccanismo di sequenza atomica con n sequenze nominate come questa:

Crea una tabella per memorizzare le tue sequenze:

CREATE TABLE sequence (
  seq_name varchar(20) unique not null,
  seq_current unsigned int not null
);

Supponendo che tu abbia una riga per "pippo" nella tabella puoi ottenere atomicamente il prossimo ID sequenza in questo modo:

UPDATE sequence SET seq_current = (@next := seq_current + 1) WHERE seq_name = 'foo';
SELECT @next;

Nessun blocco richiesto. Entrambe le istruzioni devono essere eseguite nella stessa sessione, in modo che la variabile locale @next sia effettivamente definita quando si verifica la selezione.

Altri suggerimenti

Il modo giusto per farlo è indicato nel Manuale di MySQL :

UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1);
SELECT LAST_INSERT_ID();

Siamo una società di giochi con transazioni elevate e abbiamo bisogno di questo tipo di soluzioni per le nostre esigenze. Una delle caratteristiche delle sequenze Oracle era anche il valore di incremento che poteva anche essere impostato.

La soluzione utilizza DUPLICATE KEY .

CREATE TABLE sequences (
  id BIGINT DEFAULT 1,
  name CHAR(20),
  increment TINYINT,
  UNIQUE KEY(name)
);

Per ottenere il prossimo indice:

Estrarre quanto segue con una stored procedure o una funzione sp_seq_next_val (VARCHAR) :

INSERT INTO sequences (name) VALUES ("user_id") ON DUPLICATE KEY UPDATE id = id + increment;<br/>
SELECT id FROM sequences WHERE name = "user_id";

La colonna di identità MySQL sul tavolo non è in grado di gestirla?

CREATE TABLE table_name (    ID CHIAVE PRIMARIA INTEGER AUTO_INCREMENT )

O stai cercando di usarlo per qualcosa di diverso da un semplice inserimento in un'altra tabella?

Se stai scrivendo anche usando un linguaggio procedurale (anziché solo SQL), l'altra opzione sarebbe quella di creare una tabella contenente un singolo valore intero (o intero lungo) e una procedura memorizzata che lo bloccava, selezionata da esso, lo ha incrementato e sbloccato prima di restituire il valore.

(Nota - incrementa sempre prima di restituire il valore - massimizza la possibilità di non ottenere duplicati in caso di errori - o avvolge il tutto in una transazione.)

Dovresti quindi chiamarlo indipendentemente dal tuo inserimento / aggiornamento principale (in modo che non venga catturato da alcuna transazione creata automaticamente dal meccanismo di chiamata) e quindi passarlo come parametro dove vuoi usarlo.

Poiché è indipendente dal resto delle cose che stai facendo, dovrebbe essere veloce ed evitare problemi di blocco. Anche se hai riscontrato un errore causato dal blocco (improbabile a meno che non si sovraccarichi il database), è possibile chiamarlo solo una seconda / terza volta.

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