2012-06-08 8 views
9

Sono attualmente in esecuzione la seguente dichiarazioneCosa sta bloccando "Seleziona il primo 1 * da TableName con (nolock)" dalla restituzione di un risultato?

select * into adhoc..san_savedi from dps_san..savedi_record 

Sta prendendo un dolorosamente molto tempo e mi piacerebbe vedere a che punto è così mi sono imbattuto in questo modo:

select count(*) from adhoc..san_savedi with (nolock) 

che didn' t restituire nulla in modo tempestivo così per il gusto di farlo ho fatto questo:

select top 1 * from adhoc..san_savedi with (nolock) 

Anche che sembra funzionare a tempo indeterminato. Potrei capire se ci sono milioni di record che il conteggio (*) potrebbe richiedere molto tempo, ma non capisco perché la selezione del primo record non ritorni praticamente subito considerando che ho specificato nolock.

Nel nome della divulgazione completa, dps_san è una vista che viene prelevata da una connessione odbc tramite un server collegato. Non penso che questo possa influenzare il motivo per cui non posso tornare in prima fila ma semplicemente buttarlo là fuori nel caso in cui mi sbaglio.

Quindi voglio sapere che cosa impedisce l'esecuzione di tale istruzione?

EDIT:

Come ho già detto, sì dps_san..savedi_record è una vista. Ecco ciò che fa:

select * from DPS_SAN..root.SAVEDI_RECORD 

Non è niente di più di un alias e non fa raggruppamento/ordinamento/etc quindi non credo che il problema sta qui, ma per favore mi illumini se ho sbagliato a tale proposito.

+3

Cosa fa la vista? Se esegue GROUP BY, ORDER BY o utilizza funzioni di aggregazione, potrebbe essere che selezionare la prima riga sia quasi altrettanto costoso della selezione di tutti. –

+0

Sei sicuro che SELECT INTO abbia già scritto una singola riga su disco? Forse è ancora in modalità blocco schema perché è ancora in attesa che ODBC fornisca la prima riga dalla connessione collegata. –

+0

@ AaronBertrand No, non sono sicuro. Tuttavia, posso aprire un'altra finestra di query e selezionare i record da dps_san..savedi_record tutto quello che voglio e ottenere risultati in modo che sarebbe strano se non avesse scritto alcun risultato per ora (sono passate 2 ore). –

risposta

11

SELECT le query con NOLOCK in realtà non prendono blocchi, hanno ancora bisogno di un blocco SCH-S (stabilità schema) sul tavolo (and as it is a heap it will also take a hobt lock).

Inoltre, prima che lo SELECT possa persino iniziare, SQL Server deve compilare un piano per l'istruzione, che richiede anche che esso blocchi un blocco SCH-S sul tavolo.

Poiché la transazione a esecuzione prolungata crea la tabella tramite SELECT ... INTO, contiene un blocco incompatibile SCH-M fino a quando l'istruzione non viene completata.

È possibile verificare questo, cercando in sys.dm_os_waiting_tasks mentre mentre durante il periodo di blocco.

Quando provato quanto segue in una connessione

BEGIN TRAN 

SELECT * 
INTO NewT 
FROM master..spt_values 

/*Remember to rollback/commit this later*/ 

E poi eseguire (o semplicemente cercando di visualizzare il piano di esecuzione stimato)

SELECT * 
FROM NewT 
WITH (NOLOCK) 

in una seconda query lettura è stata bloccata.

SELECT wait_type, 
     resource_description 
FROM sys.dm_os_waiting_tasks 
WHERE session_id = <spid_of_waiting_task> 

Mostra il tipo di attesa è davvero SCH_S e la risorsa di blocco SCH-M

wait_type  resource_description 
---------------- ------------------------------------------------------------------------------------------------------------------------------- 
LCK_M_SCH_S  objectlock lockPartition=0 objid=461960722 subresource=FULL dbid=1 id=lock4a8a540 mode=Sch-M associatedObjectId=461960722 
+1

+1 ma quasi non l'ho fatto per "while" :-) –

+0

@AaronBertrand - Grazie, pensa "mentre" è OK per gli inglesi da usare [secondo Wikipedia] (http://en.wikipedia.org/wiki/ Mentre)! –

+0

Ciò non significa che mi debba piacere. Gli inglesi possono anche usare "while" giusto? :-) –

2

È possibile che non ci siano blocchi ... Se dps_san..savedi_record è una vista, potrebbe essere necessario molto tempo per l'esecuzione, perché potrebbe accedere alle tabelle senza utilizzare un indice, oppure può essere l'ordinamento di milioni di record, o qualunque ragione. Quindi la tua query, anche una semplice sommità o conteggio, sarà veloce solo quanto quella vista può essere eseguita.

+0

La selezione è rispetto a una tabella che viene popolata, non a una vista. –

+0

Vedi la mia modifica. La vista seleziona *. Nessun raggruppamento/ordinamento/o qualsiasi cosa che potrebbe causare la necessità di eseguire la scansione dell'intera tabella prima di restituire risultati o qualcosa del genere. –

+0

@AaronBertrand Ho pensato che stesse dicendo la stessa cosa che hai suggerito, che potrebbe non essere ancora riuscito a inserire alcun record. –

2

Alcuni aspetti da considerare qui. Dps_san..savedi_record è una visualizzazione? Se è così, potrebbe richiedere molto tempo per ottenere i tuoi dati. L'altra cosa che posso pensare è che stai cercando di creare una tabella temporanea utilizzando la sintassi select into, che è una cattiva idea. La sintassi select * into ... bloccherà il tempdb per la durata della selezione.

Se si sta creando la tabella utilizzando tale sintassi, esiste una soluzione alternativa. In primo luogo, creare la tabella lanciando where 1=0 alla fine della sua dichiarazione iniziale:

select * into ... from ... where 1=0 

Questo creerà la prima tabella (che è veloce), che consente di insert into perché la tabella esiste ora (senza penali del tempdb bloccaggio per la durata della query).

+0

@AaronBertrand Hai ragione signore, grazie per averlo corretto per me (ho dimenticato che può essere usato solo per creare un tavolo). [Select Into ... Reference] (http://msdn.microsoft.com/en-us/library/ms190750 (v = sql.105) .aspx) – SPFiredrake

+0

Grazie, darò uno scatto. –

2

Trovare il session_id che sta eseguendo l'select into:

SELECT r.session_id, r.blocking_session_id, r.wait_type, r.wait_time 
    FROM sys.dm_exec_requests AS r 
    CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS t 
    WHERE t.[text] LIKE '%select%into%adhoc..san_savedi%'; 

Questo dovrebbe farvi sapere se un'altra sessione sta bloccando la selezione in o se ha un tipo di attesa che sta causando un problema.

È possibile ripetere il processo in un'altra finestra per la sessione che sta tentando di eseguire la selezione. Sospetto che Martin abbia ragione e che il mio precedente commento sul blocco dello schema sia pertinente.

+0

s dovrebbero supporre essere. –

+0

@BrandonMoore si –

Problemi correlati