2009-04-27 3 views
15

Stiamo provando ad avere una tabella transazionale che inserisce solo nuovi record inseriti regolarmente.Perché SQL Server 2008 blocca SELECT su INSERT di transazioni lunghe?

Questa semplice tabella ci richiede di aggiungere continuamente nuovi record nel tempo. Si prevede che il volume delle transazioni in questa tabella sia piuttosto elevato e inoltre potrebbero esserci importazioni periodiche di transazioni batch (> 1000) che potrebbero richiedere più secondi.

Da questi dati facciamo un insieme di istruzioni select che raggruppano colonne diverse per restituire i valori richiesti.

Dai test iniziali abbiamo riscontrato un collo di bottiglia da correlare a SQL Server che blocca i nostri SELECT quando ci si trova nel mezzo di una transazione di INSERTS.

Di seguito è riportato un semplice esempio che può essere eseguito per illustrare il problema.

- Semplice DB Tabella

create table LOCK_TEST (
LOCK_TEST_ID int identity , 
AMOUNT int); 

- Eseguire questo nella finestra 1 di query

begin tran 
insert into LOCK_TEST (AMOUNT) values (1); 
WAITFOR DELAY '00:00:15' ---- 15 Second Delay 
insert into LOCK_TEST (AMOUNT) values (1); 
commit 

- In Query 2 run questo in parallelo

select SUM(AMOUNT) 
from LOCK_TEST; 

mi si aspetterebbe Interroga 2 per tornare subito, con 0 fino al completamento della query 1, quindi visualizza 2. Non vogliamo mai vedere 1 restituito dalla seconda query.

Le risposte che abbiamo esaminato riguardano WITH (NOLOCK) sull'istruzione select. Ma questo viola i confini della transazione, e le informazioni restituite potrebbero essere di natura finanziaria e non desideriamo vedere dettagli non archiviati nelle nostre query.

Il mio problema sembra essere sul lato INSERT ...
Perché l'Inserisci Blocco SELECT, anche se non è di modificare i dati esistenti?

Domanda punti bonus: Si tratta di una "funzionalità" di SQL Server o lo troveremmo anche su altri tipi di database?

UPDATE ora ho avuto il tempo di trovare un database Oracle locale ed eseguire lo stesso test semplice. Questo test pass è come mi aspetterei.

Ie posso correre domanda tutte le volte che voglio, e restituirà nulla fino a quando la prima operazione di commit, poi ritorna 2.

C'è un modo per rendere il lavoro di SQL Server in questo modo? o dobbiamo spostarci su Oracle?

+0

quali indici avete su queste tabelle? hai una manutenzione periodica dell'indice? –

+0

Al momento non ci sono indici. Vedere il semplice esempio elencato in questo post, nient'altro che la semplice tabella a 2 colonne, l'inserimento di base e select sono usati per ricreare questo problema. – stevemac

risposta

12

questo comportamento di blocco è una funzionalità di SQL Server. Con 2005 e versioni successive, è possibile utilizzare row level versioning (che è quello che viene utilizzato in modo predefinito su Oracle) per ottenere lo stesso risultato & non bloccare la selezione. Ciò mette a dura prova il tempdb perché tempdb mantiene il controllo delle versioni a livello di riga, quindi assicurati di tenerne conto. Per rendere SQL si comportano nel modo desiderato a, eseguire questo:

ALTER DATABASE MyDatabase 
SET ALLOW_SNAPSHOT_ISOLATION ON 

ALTER DATABASE MyDatabase 
SET READ_COMMITTED_SNAPSHOT ON 
+0

http://stackoverflow.com/a/4118803/2319909 –

4

Questo comportamento è completamente standard in SQL Server e Sybase (almeno).

Le modifiche dei dati (inserimento, aggiornamento, eliminazione) richiedono exclusive locks.ciò causa il blocco dei lettori:

Con un blocco esclusivo (X), nessun'altra transazione può modificare i dati; leggere le operazioni può avvenire solo con l'uso del suggerimento NOLOCK o leggere il livello di isolamento non eseguito .

Con SQL Server 2005 e versioni successive, è stato introdotto l'isolamento dello snapshot (ovvero il controllo delle versioni delle righe). Da MS BOL: Understanding Row Versioning-Based Isolation Levels. Ciò significa che un lettore ha gli ultimi dati commessi, ma se poi vuoi ricomprare, per esempio, potresti scoprire che i dati sono sbagliati perché sono cambiati nella transazione di blocco.

Ora, questo è il motivo per cui è consigliabile mantenere le transazioni in breve. Ad esempio, elaborare solo ciò che è necessario iniziare fra/commit, non inviare email da trigger ecc

Edit:

bloccaggio come questo accade tutto il tempo in SQL Server. Tuttavia, il blocco per troppo tempo diventa un blocco che riduce le prestazioni. Troppo a lungo è soggettivo, ovviamente.

+0

La transazione è breve, ma il volume di essi causa il blocco che non dovrebbe essere richiesto affatto. Vedi il commento sulla domanda su Oracle. – stevemac

+0

Spostati su Oracle se lo desideri. Se riesci a passare a Oracle semplicemente, sospetto che il tuo SQL non sia ottimale, stai facendo il giro da un client all'altro o qualcosa che sta causando un blocco eccessivo. – gbn

+1

Come può un esempio così semplice non essere ottimale? Dal semplice esempio a condizione che blocchi ancora. Puoi suggerire come cambio l'esempio fornito per renderlo ottimale? Si prega di notare che non ci saranno MAI aggiornamenti a questi dati, solo nuovi inserti. – stevemac

1

Questo esiste anche in MySQL. Ecco la logica dietro: se si esegue un SELECT su alcuni dati, si prevede che funzioni su un set di dati aggiornato. Ecco perché INSERT genera un blocco a livello di tabella (a meno che il motore non sia in grado di eseguire il blocco a livello di riga, come ad esempio innodb). Ci sono modi per disabilitare questo comportamento, in modo da poter fare "letture sporche", ma sono tutte specifiche del software (o anche del motore di database).

+1

Sono d'accordo, ma voglio anche che riconosca le transazioni. Dal mio punto di vista i nuovi record (quelli della transazione) non esistono, e forse mai lo faranno. Perché il database blocchi su dati che (dal mio punto di vista) non esistono sembra sbagliato. Capisco che se stavo aggiornando i dati in un posto e selezionandolo da altrove, potrei voler aspettare l'aggiornamento, ma voglio controllarlo ... Soprattutto con INSERTING. Sembra che Oracle faccia come mi aspetto. Sto ancora cercando di capire se SQL Server può. – stevemac

1

Ho anche imbattuto in questo problema. Dopo un'indagine, sembrava che non fossero i dati a essere bloccati di per sé, ma l'indice cluster che veniva modificato a seguito dell'inserto. Poiché l'indice cluster risiede nelle pagine di dati, anche le righe di dati associate sono bloccate.