siquellando

...scoperte e considerazioni Sql di uno sviluppista
(un po' sviluppatore e un po' sistemista)
Elenco build Sql2005

Segnalo che sul "sempre ottimo" sito http://www.sqlservercentral.com/ ieri e' stato pubblicato un elenco delle build di Sql 2005, una di quelle cose che, quando ne ho bisogno, non ricordo mai dove trovare Sad

L'elenco lo trovate qui: http://www.sqlservercentral.com/articles/Administration/2960/

 

Feature "SAS like" in Sql2008

Buone news per i Sassisti in ascolto che lavorano in SqlServer: nella versione Sql2008 saranno presenti due funzionalita' che ricordano molto da vicino cio' che si ha (da illore tempo) a disposizione in SAS.

Mi riferisco allo statement MERGE che consente, in un singola operazione atomica, di effettuare Insert, Delete ed Update su una tabella target sulla base dei dati presenti in una tabella source.

E' qualcosa che consente facilmente in Sql di effettuare quelle operazioni di aggiornamento che si fanno in un data step SAS  con lo statement merge [stesso nome, appunto Smile] e l'opzione IN dei dataset.

Ecco un esempio di come aggiornare le informazioni presenti nella tabella Attivita sulla base di quelle presenti nella tabella UpdAttivita

/* setup test */
use tempdb
go


create table dbo.Attivita (Id int, Label varchar(20),Durata int);
go
create table dbo.UpdAttivita (Id int, Label varchar(20),Durata int);
go

insert into dbo.Attivita values (1,'Alfa',120),(2,'Beta',200),(3,'Gamma',80);

insert into dbo.UpdAttivita values (4,'Echo',10),(2,'Beta',210),(3,'GammaNew',801);


/* applico le variazioni */
merge into dbo.Attivita AS TGT
 using dbo.UpdAttivita AS SRC
 
 on TGT.id = SRC.id

when MATCHED then

  update set
    TGT.label = SRC.label,
    TGT.durata = SRC.durata

when NOT MATCHED then

  insert (id, label, durata)
  values (SRC.id, SRC.label, SRC.durata)

when SOURCE NOT MATCHED then
 delete
;

/* verifica */
select * from dbo.Attivita;

 Per i curiosi in SAS, in questo caso, bastava scrivere:

data Attivita;

merge Attivita (in=a) UpdAttivita(in=b);

by Id;

if a and not b then delete;

run;

 Che in effetti e' un po' piu' compatto Stick out tongue

 

L'altra funzionalita' introdotta e' quella dei GROUPING SETS che ci fanno ritrovare praticamente "pari pari" la Proc Summary all'interno di SqlServer.

Appoggiandosi a tale funzionalita' possiamo ottenere, con un unica query, piu' raggruppamenti, uno per ogni combinazione dei campi indicati nell'istruzione  Grouping Sets del Group By che diviene l'equivalente dell'istruzione CLASS della Proc Summary.

Ad esempio se volessimo, in un colpo solo, la somma delle vendite della tabella Vendite sia per IdProdotto che per PuntoVendita insieme alle somme per ogni combinazione di PuntoVendita e IdProdotto ed anche il Totalone con i Grouping Sets possiamo scrivere:

use tempdb
go

-- creazione tabella di esempio
if OBJECT_ID ('dbo.Vendite') is not null drop table dbo.Vendite;

create table dbo.Vendite (
 PuntoVendita varchar(20),
 IdProdotto  int,
 Quantita  int
 );
go

-- inserimento dati esempio
insert into dbo.Vendite (PuntoVendita,IdProdotto,Quantita)
Values
('Milano',1,120),
('Milano',2,124),
('Milano',3,210),
('Roma',1,300),
('Roma',2,155),
('Roma',3,38),
('Napoli',2,35)
;

/* calcolo i vari totali */


select  PuntoVendita, IdProdotto, SUM(Quantita) as Quantita
 from dbo.Vendite
 group by
 GROUPING Sets(
 (),
 (PuntoVendita ),
 (IdProdotto),
 (PuntoVendita,IdProdotto )
 )
 order by PuntoVendita , IdProdotto
 ;

Per gli interessati l'equivalente SAS sarebbe:

proc Summary data = Vendite print sum;

var Quantita;

class PuntoVendita  IdProdotto ;

run;

 

Mi piacciono, si mi piacciono veramente molto queste nuove possibilita' di Sql2008 Drinks


 

Posted: giu 26 2008, 01.58 by orsocurioso | with no comments
Filed under: ,
Virtual PC che non appare

Ieri ho litigato con Virtual PC (versione 6.0) che, senza una ragione apparente, non presentava piu' la finestra di console: l'icona stava "comodamente" funzionante nella system tray, ma se cliccavo due volte o chiedevo di vedere la console... Nisba Sad 

Roba da non crederci!!

Dopo un po' di fatica (e la solita mezz'ora buttata) con santo Google la soluzione mi e' stata fornita da questo post http://marcellotonarelli.wordpress.com/2007/06/02/show-microsoft-virtual-pc-2007-console/ di Marcello Tonarelli (GRAZIE).

Pari pari dal suo blog riporto la soluzione al fastidioso problema:

Dare un occhio al file di configurazione

C:\Documents and Settings\__Name_Of_Your_Windows_Account__\Application\Data\Microsoft\Virtual PC\Options.xml

e verificare che i valori delle dimensioni e della posizione per la sezione <console> "abbiano senso" (io mi ritrovavo la left e right position con valori stellari invece di un sano 0).

Buoni valori sono ad esempio:

<console>
<height type=”integer”>575</height>
<left_position type=”integer”>0</left_position>
<top_position type=”integer”>0</top_position>
<visible type=”boolean”>true</visible>
<width type=”integer”>359</width>
</console>

 

Morale (la solita):

in rete c'e' un mucchio di gente che ti da una mano e ci consente di sopravvivere con le bizze  del software Smile

 

 

Posted: mag 13 2008, 06.50 by orsocurioso | with no comments
Filed under:
Nested Transition ... attenzione, non ci sono

In questi giorni parlando con vari utenti ho realizzato che, a volte, c'e' un po' di confusione in merito alla possibilita' di avere transazioni annidate in Sql Server.

Forse vale la pena di fare un po' di chiarezza: SqlServer NON supporta "Transazioni Annidate".

In altre parole per ciascuna connessione puo' esistere solo una transazione attiva.

E il fatto che sia possibile (almeno sintatticamente) sottomettere piu' statement BEGIN TRANSACTION complica e confonde le cose Huh?

In realta' ogni volta che viene sottomesso un BEGIN TRAN SqlServer semplicemente incrementa un contatore interno il cui valore e' recuperabile con una select sulla funzione @@trancount.

Ad ogni commit il valore di @@trancount diminuisce di un unita' e solo l'ultimo commit (che riporta @@trancount a zero) committa realmente la transazione.

In compenso qualunque rollback provoca l'annullamento di tutte le operazioni a partire dal primo begin tran (ovvero viene annullata la transazione piu' esterna).

Pertanto sottomettendo il seguente codice:

begin tran;

insert into Test values (1);

begin tran;

insert into Test values (2);

- rolback di tutto (anche l'insert col valore 1)

rollback;

-- questo commit da errore: la transazione e' chiusa

commit;

Nella tabella Test non verra' inserito alcun valore, in quanto il primo rollback cancella tutte le attivita' iniziate con la transazione piu' esterna.

 

Inoltre, per committare davvero, bisogna prestare attenzione a sottomettere un numero di COMMIT uguale al numero di BEGIN TRAN  (@@trancount) altrimenti si rischia di lasciare aperta la transazione con tutti i pericoli di lock che seguono. 

 

Attenzione che ci sono situazioni (ad esempio se l'utente ha dato un cancel) in cui, anche se viene generato un errore, non viene chiusa la transazione Surprise  Pertanto e' buona norma verificare se ci sono transazioni attive prima di risottomettere nuovamente un BEGIN TRAN e trovarsi con qualche "parentesi non chiusa" Smile

 

Sql 2008 le mie Top 5 +1

Mi accodo anch'io al post di Andrea e riporto la mia top five: forse non sono le novita' piu' eclatanti, ma ripensando alla mia attivita' in Sql degli ultimi tempi quelle che seguono sono le cose che piu' mi mancavano...

  1. Statement MERGE
  2. Date & Time datatypes
  3. Table-Valued parameters
  4. Grouping Sets
  5. Transparent Data Encryption

e la 5 + 1 e' il Change Data Capture

e la 6 +1 e' il Resource Governor ... e la 7 +1 ... Big Smile

 

Nuovo sito dedicato a Sql

Come comunicato nel blog della Delaney http://sqlblog.com/blogs/kalen_delaney/archive/2008/01/19/did-you-know-a-terrific-new-community-website.aspx in rete e' nato un nuovo sito dedicato a risorse tips & tricks per Sql Server.

Il sito e' questo: http://www.sqlcommunity.com

Da un primo occhio mi sembra valido, vediamo se col tempo manterra' le promesse.

Posted: gen 23 2008, 04.46 by orsocurioso | with 2 comment(s)
Filed under:
Anche il TRUNCATE e' loggato

Spesso si sente dire che determinate operazioni (il truncate, per esempio) NON vengono loggate in Sql...  Tale affermazione e’ da prendere “con le pinze” in quanto e’ quasi sempre falsa. Wink

 

Sql Server (almeno in recovery model FULL o BULK_LOGGED)  logga tutte le operazioni che vengono effettuate sui dati e sugli oggetti del database in quanto, altrimenti, non potrebbe, durante il restoring, ricostruire correttamente e completamente lo stato del database.

 

Se mai quello che cambia e’ il modo in cui l’operazione viene loggata, ovvero quali informazioni vengono registrate nel log.

 

Un esempio “esemplare” di cio’ ci e’ proprio fornito dall’istruzione TRUNCATE: in questo caso SQL non ha la necessita’ di loggare ogni singolo delete (che in effetti non viene compiuto), ma registrera’ la singola operazione truncate (che corrisponde al deallocamento delle pagine su cui sono memorizzati i dati della tabella).

 

Questo “minimum logging” consente comunque a Sql di garantire la transazionalita’ dell'esecuzione e la possibilita' del restore.

 

Pertanto anche l'istruzione TRUNCATE puo' essere eseguita all’interno di una transazione e subisce la fase di Redo durante il restore.

 

Potete verificare facilmente entrambe le cose con il seguente codice.

 

USE [master]

GO

-- Creazione db e tabelle di test

IF EXISTS (SELECT name FROM sys.databases WHERE name = N'TestTruncate')

DROP DATABASE TestTruncate

GO

 

CREATE DATABASE TestTruncate ON PRIMARY

( NAME = N'TestTruncate', FILENAME = N'C:\Temp\TestTruncate.mdf' ,

SIZE = 5MB , MAXSIZE = UNLIMITED, FILEGROWTH = 1MB )

LOG ON

( NAME = N'TestTruncate_log', FILENAME = N'C:\Temp\TestTruncate_log.ldf' ,

SIZE = 1MB , MAXSIZE = UNLIMITED, FILEGROWTH = 1MB)

GO

-- setto il recovery model a FULL

alter database TestTruncate set recovery Full;

GO

 

use TestTruncate

go

-- Creo la tabella (con un campo identity) e inserisco dei record

create table dbo.ForTruncateExample

(Codice int identity (1,1),

Valore varchar(10))

go

insert into dbo.ForTruncateExample values ('Alfa');

insert into dbo.ForTruncateExample values ('Beta');

select * from dbo.ForTruncateExample;

-- truncate sotto transazione

begin tran;

truncate table dbo.ForTruncateExample ;

-- non ci sono piu' valori

select * from dbo.ForTruncateExample;

rollback;

-- la truncate e' stata "rollbackata" !!

select * from dbo.ForTruncateExample;

-- verifico che anche l'identity continua a funzionare

insert into dbo.ForTruncateExample values ('Gamma');

select * from dbo.ForTruncateExample;

 

-- backup dati

backup database TestTruncate to disk = 'c:\temp\TestTruncate_FULL01.bck' with init;

-- Effettuo la truncate e poi backupp il log

truncate table dbo.ForTruncateExample ;

backup log TestTruncate to disk = 'c:\temp\TestTruncate_Log01.bck' with init;

-- restore Dati + Log

use master;

go

restore database TestTruncate from disk = 'c:\temp\TestTruncate_FULL01.bck' with NORECOVERY , REPLACE;

restore log TestTruncate from disk = 'c:\temp\TestTruncate_Log01.bck' with RECOVERY;

-- la tabella e' troncata

select * from TestTruncate.dbo.ForTruncateExample;

 

Ulteriori interessanti notizie sulla TRUNCATE (e sulle differenze con la DELETE) le trovate in questo articolo http://www.sqlservercentral.com/links/335083/14505

Un log che non cresce anche in FULL logging

Posto una particolarita' del comportamento del file di log la cui utilita' pratica rasenta lo zero, ma puo' essere utilizzata per vincere un caffe' facendo una scommessaBig Smile

Domanda: e' possibile che un database in cui vengono effettuate numerose operazioni di scrittura, settato in modalita'di recovery FULL e per cui non venga mai effettuato un backup del log  non presenti un aumento delle dimensioni del suo file di log  (o per lo meno esso non tenda ad "esplodere") ?

Risposta: (sorprendente):  SI.

Capita in una condizione piuttosto particolare: se non e' mai stato effettuato un backup completo dei dati da quando il database e' in recovery model FULL.

 

Questo e' dovuto al fatto che, in realta',  la condizione che il log "non cresca", ovvero che recuperi via via lo spazio utilizzato dalle transazioni committate ed effettivamente scritte nel database (truncation del log) non e' legata "esattamente" al modello di recovery Surprise , ma piu' precisamente al fatto che SQL Server abbia dedotto che, per quel database, non viene mantenuta una sequenza di backup del log.

In altre parole, se SQL capisce che non abbiamo intenzione di utilizzare il log nella nostra strategia di backup-restore, correttamente non si preoccupa (se ne frega...)  di salvare le transazioni gia' scritte nel database (dato che non ci servono per il restore) e recupera appena puo', con un bel truncate, lo spazio a loro allocato.

Ok, e quando SQL puo' essere sicuro che non ci interessa il restore dal log ??? Nei seguenti tre casi:

  • Lo richiediamo espressamente scegliendo il modello di recovery SIMPLE
  • Buttiamo via i dati del log con l'istruzione backup log with no_log ( Sad opzione deprecata che non sara' piu' supportata nelle prossime versioni)

e, dulcis in fundo...

  • Non abbiamo MAI fatto un backup full dei dati.
    (se non abbiamo il back up di base come facciamo ad applicargli il restore del log !!??!!) 

 

Eh, si, c'e' poco da fare SqlServer e' ... furbo !! Party!!!

 

PS: vi interessa sapere (in Sql2005) quali database sono in questa situazione (ovvero in autotruncate mode) ?  Lo vedete da questa select:

SELECT db_name(database_id)

FROM sys.database_recovery_status

WHERE last_log_backup_lsn is NULL

 

Script per recuperare le dimensioni dei log

Ho modificato uno script pubblicato dalla Delaney per farmi restituire, per tutti i database, le dimensioni dei dati, del file di log, la sua % di occupazione ed il modello di recovery attivo.

Lo script, valido per Sql2005, e' veramente semplice, ma potrebbe comunque essere utile per cui eccolo.

 

 /* restituisce per tutti i database le dimensioni dei dati, del log la % di occupazione del log ed il modello di recovery */

select rtrim (pc1.instance_name) as [Database Name],

pc3.cntr_value/1024.0 as [Data Size (MB)],

pc1.cntr_value/1024.0 as [Log Size (MB)],

cast (pc2.cntr_value*100.0/pc1.cntr_value as dec (5,2)) as [Log Space Used (%)],

db.recovery_model_desc

 

from sys.dm_os_performance_counters as pc1,

sys.dm_os_performance_counters as pc2,

sys.dm_os_performance_counters as pc3,

sys.databases as db

 

where pc1.instance_name = pc2.instance_name

and pc1.instance_name = pc3.instance_name

and pc1.instance_name = db.name

and pc1.counter_name = 'Log file(s) Size (KB)'

and pc2.counter_name = 'Log file(s) Used Size (KB)'

and pc3.counter_name = 'Data File(s) Size (KB)'

and pc1.cntr_value > 0

order by pc1.instance_name;

 

Il recovery model SIMPLE

In merito al recovery model SIMPLE spesso girano dubbi e spesso capita di sentirsi chiedere cosa logga e se le sue dimensioni crescono  e perche' crescono  e quando si "sgonfia" etc etc. Sperando di fare cosa utile in questo post provero' a fare un po' di chiarezza in merito...

Innazitutto chiariamo che una modalita' di logging SIMPLE non significa che non loggo ... Tutt'altro: SIMPLE significa solo che il transaction log non potra' essere utilizzato in fase di restore (infatti in questa modalita' non e' concesso il backup del log), ma che comunque viene assicurata tutta l'attivita' relativa alla gestione delle transazioni ... e ci mancherebbe che non lo facesse !!!! Big Smile

Pertanto, anche in questa modalita', il transaction log conterra' tutte le informazioni necessarie a Sql per poter gestire un eventuale roll back. Questo comporta che il file di log avra' una dimensione tale da memorizzare tutte le transazioni non ancora committate o, piu' precisamente, conterra' "almeno" tutte le transazioni avvenute a partire dalla piu' vecchia presente ancora non committata.

Per questa ragione, in presenza di transazioni ricche di dati, anche in modalita' SIMPLE il file di log crescera' e potrebbe assumere dimensioni anche elevate.

La differenza con le altre due modalita di recovery (FULL e BULK_INSERT) risiede nel fatto che, man mano che le transazioni vengono committate lo spazio a loro associato viene riutilizzato per memorizzare nuove transazioni.[per dirla piu' correttamente viene riutilizzato lo spazio associato alle transazioni antecedenti alla piu' vecchia non committata]. Questo in FULL e BULK_INSERT avviene dopo il backup del log.

 

Nella modalita' SIMPLE periodicamente e con una frequenza legata alle dimensioni del file di log e al suo grado di riempimento, viene verificata la posizione della transazione attiva piu' vecchia e viene marcato come riutilizzabile lo spazio del log allocato a tutte le transazioni antecedenti a questa. Tale attivita' prende il nome di Troncamento (truncation) del log.

Il Log truncation e' un attivita' di tipo logico: ad essa non e' associata una riduzione fisica del log.

La diminuzione del file di log e' legata all'attivita' di Shrink che, se non e' abilitata tramite l'opzione AUTO_SHRINK ON (cosa da non fare MAI Angry), avverra' solo dietro un preciso comando (ad esempio un DBCC SHRINKDATABASE).

Detto cio' bisogna ricordare che il recovery model SIMPLE, visto che non consente il recovery tramite log, andrebbe usato raramente: di fatto solo con DB in read only o di test... Averlo in produzione significa sapere che, in caso di failure, verranno perse tutte le transazioni intercorse dall'ultimo backup (full o differenziale) cosa che ritengo sia accettabile in ben poche situazioni....

 

Di seguito, per i curiosi, un po' di codice "pronto all'uso" per vedere la crescita del file di log in modalita' SIMPLE.

Ciao.

-- Test sul recovery model Simple

USE [master]

GO

-- Creazione db e tabelle di test

-- Il file di log e' VOLUTAMENTE inizializzato piccolo con bassa crescita

-- per valutarne l'aumento di dimensioni

IF EXISTS (SELECT name FROM sys.databases WHERE name = N'TestRecoverySimple')

DROP DATABASE TestRecoverySimple

GO

 

CREATE DATABASE TestRecoverySimple ON PRIMARY

( NAME = N'TestRecoverySimple', FILENAME = N'C:\Temp\TestRecoverySimple.mdf' ,

SIZE = 20480KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1MB )

LOG ON

( NAME = N'TestRecoverySimple_log', FILENAME = N'C:\Temp\TestRecoverySimple_log.ldf' ,

SIZE = 1MB , MAXSIZE = UNLIMITED, FILEGROWTH = 1MB)

GO

-- setto il recovery model a SIMPLE

alter database TestRecoverySimple set recovery Simple;

GO

-- disabilito l'auto shrink del DB(da non abilitare mai)

alter database TestRecoverySimple set Auto_Shrink OFF;

GO

 

--- Creo la tabella di test

use TestRecoverySimple

GO

create table BigInsert (Id int identity(1,1),

Data datetime default getdate(),

Valore varchar (8000));

GO

-- creo la store procedure di inserimento record

create procedure fpsp_InsertBigRecord (@NumRecord int, @Testo char(1))

as

declare @Counter int

set @Counter = 1

while @Counter <= @NumRecord Begin

insert into dbo.BigInsert (Valore) values (replicate(@Testo,8000));

set @Counter = @Counter + 1;

end

GO

-- creo la Store procedures (per comodita) che presenta i dati sul log

create procedure fpsp_ShowLogDimension (@InstanceName varchar(50))

as

select Instance_Name, Counter_name, cntr_value

from sys.dm_os_performance_counters

where instance_name= 'TestRecoverySimple'

and cntr_type = 65792

and Counter_Name like '%Log%'

;

GO

-- leggo i valori iniziali del log

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- 1016 Kb (40% utilizzato), 0 Shrinks, 0 Growths, 1 Truncation

--- effettuo degli insert

exec fpsp_InsertBigRecord 2000, 'A';

--Leggo le dimensioni del log

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- NON e' aumentato: 1016 Kb (53% utilizzato), ma ha subito 75 Truncations

 

-- Inserimenti sotto transazione

begin tran;

exec fpsp_InsertBigRecord 100, 'B';

-- Rileggo le dimensioni del log

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- E' aumentato: 2040 Kb (73% utilizzato), 1 Growths e 2 truncation rispetto a prima (ora il valore e' 77)

commit;

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- L'autoshrink e' disabilitato per cui Non scende la dimensione (2040 Kb)

-- altri inserimenti senza transazioni attive

exec fpsp_InsertBigRecord 2000, 'C';

-- valuto di nuovo il log

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- Nessun inserimento da committare: Non ha avuto bisogno di aumentare (2040 Kb)

-- e' solo aumentato il numero di truncation effettuate (ora 96)

 

-- effettuo uno shrink

DBCC SHRINKDATABASE (TestRecoverySimple);

-- valuto di nuovo il log

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- le dimensioni sono scese:1016 Kb (36% utilizzato)

-- nuovi inserimenti sotto transazione

begin tran;

exec fpsp_InsertBigRecord 200, 'D';

-- valuto di nuovo il log

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- ha subito due grow (il valore ora e' 3) le dimensioni sono: 3064 Kb (83% usato) - log truncation = 123

commit;

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- 3064 kb (72%)

--effettuo lo shrink

DBCC SHRINKDATABASE (TestRecoverySimple);

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- ritorno alle dimensioni minime iniziali 1016 kb (35% occupato)

 

-- effettuo un select into

select * into dbo.NewBigTable from dbo.BigInsert;

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- Log size 2040 Kb (61% usato) l'attivita' di insert ha richiesto piu' spazio per il log

-- nuovo select into

select * into dbo.NewBigTable2 from dbo.BigInsert;

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- Non e' aumentato l'operazione era uguale a prima e non ha richiesto altro spazio

-- Log size 2040 Kb (57% usato)

 

-- nuovo select into

select * into dbo.NewBigTable3 from dbo.BigInsert;

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- Continua a non aumentare 2040 Kb (61% usato)

 

-- ora select into sotto transazione

begin tran

-- 1° select into

select * into dbo.NewBigTable4 from dbo.BigInsert;

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- non aumenta

---2° select into

select * into dbo.NewBigTable5 from dbo.BigInsert;

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- siamo sotto transazione la richiesta di spazio aumenta 3064 Kb (78% usate)

---3° select into

select * into dbo.NewBigTable6 from dbo.BigInsert;

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- siamo sotto transazione la richiesta di spazio aumenta ancora 4088 Kb (83% usate)

---4° select into

select * into dbo.NewBigTable7 from dbo.BigInsert;

exec fpsp_ShowLogDimension 'TestRecoverySimple';

-- siamo sotto transazione la richiesta di spazio aumenta ancora 5112 Kb (83% usate)

-- annullo

Rollback

exec fpsp_ShowLogDimension 'TestRecoverySimple';

Restore di un DB Master corrotto

Questa e' carina...

In presenza di un database Master corrotto l'istanza di SqlServer potrebbe non partire, pertanto sara' necessario procedere al restore di una copia valida del Master backuppata precedentemente. Ma, per poter effettuare il restore, occorre che l'istanza di Sql sia su... e ... ci troviamo in una situazione di stallo Surprise

Una soluzione drastica e' reinstallare SqlServer, ma esiste una via piu' comoda: reinstallare solo i DB di sistema tramite il seguente comando (documentato nel BOL)

start /wait <CD or DVD Drive>\setup.exe /qn INSTANCENAME=<Instance> REINSTALL=SQL_Engine REBUILDDATABASE=1 SAPWD=<NewStrongPassword> e, poi, procedere al restore del "nostro" master.

Questa info l'ho letta nel seguente post dedicato a questa "complicata" situazione: http://blogs.msdn.com/sqlserverstorageengine/archive/2006/09/26/772550.aspx 

Inoltre in quel post viene anche illustrato il procedimento, leggermento piu' lungo, da seguire qualora ci si trovi in presenza di un Sql Express

Non se la cosa era nota a tutti (tranne che a me)... In ogni caso mo' me la sono appuntata qui.. non si sa mai.....

 

Logging del rebuild index

Se il database e' settato in recovery model FULL tutte le scritture legate ad un create index o a un rebuild verranno tracciate nel file di log. Pertanto il transaction log puo' aumentare le proprie dimensioni in modo molto elevato (pensate alle scritture legate ad un indice cluster) aumentando anche i tempi necessari al rebuild stesso.

Questo non accade se il recovery model e' settato a BULK_LOGGED: in tal caso viene tracciato solo il fatto che l'operazione e' stata compiuta oltre ad alcune altre informazioni (tipo gli extended modificati) che serviranno a garantire la corretta esecuzione di un eventuale restore. In tal modo anche la ricreazione degli indici risulta piu' veloce.

Per quello che mi riguarda, dopo aver costruito ed attivato un piano di manutenzione che ricreava un bel po' di indici e essermi trovato un file transaction "esploso" Sad ho pensato bene di portare il recovery a BULK_LOGGED prima di iniziare l'attivita' e di riportarlo a FULL una volta terminata la manutenzione.

In tal modo le dimensioni del file di log non crescono (se non in minima parte) durante le operazioni di rebuild degli indici e sono anche un po' piu' veloci, ma...attenzione: quando viene effettuato il backup del transaction log Sql provvede a fare in modo che nel file di backup siano presenti tutte le infomazioni necessarie al restore. Pertanto recupera tutte le modifiche fatte alle pagine e le riporta nel file di backup.

Quindi il file di log rimane "snello", ma il suo backup si ingrossa fino ad assumere le dimensioni che avrebbe avuto il log in un recovery FULL ed il tempo di backup si allunga.

 In tal modo e' garantito un restore completo sia con il modello FULL che con il BULK_LOGGED con tempi analoghi.

Oltre alla creazione degli indici anche diverse altre operazioni (bcp, BULK INSERT, SELECT INTO...) vengono loggate in modo differente nei due modelli di recovery e, questa, e' una buona ragione per approfondire e capire meglio le differenze tra FULL e BULK_LOGGED.

(Se lo faro' sara' argomento per un prossimo post)

Quanto detto vale per Sql2005, ho il sospetto che in Sql2000 le cose fossero un po' differenti, ma non ho avuto il modo di verificarlo (altro post in arrivo ?) 

Buon backup a tutti !! Smile

truncate table con campo identity

Mi sono imbattuto in un comportamento di SqlServer che, di prima battuta, non mi aspettavo, anche se riflettendoci un momento e' assolutamente corretto e sensato (oltre che documentato). Comunque lo posto perche' potrebbe essere inaspettato anche per qualcun altro.

Se fate un "truncate table" di una tabella che contiene un campo identity il suo valore viene riazzerato e, al primo insert, lo trovate valorizzato al suo seed iniziale. In altre parole la truncate fa "perdere" a Sql il valore attuale del contatore,

 

inaugurazione

Da questo luogo provero' anch'io a segnalare caratteristiche e situazioni Sql che mi hanno colpito o semplicemente interessato. Un modo per ricordarsele e, magari, in qualche caso, essere utile.

Ma sono solo uno sviluppista quindi non aspettatevi nulla di straordinario: in fondo unisco le incompentenze di entrambe le figure Smile  ... Pero', non si sa mai, come dice un vecchio saggio tosco-emiliano  "ho visto a volte che anche un topo sa ruggire ed anche un' aquila precipitata".... per cui... stay tuned !!

 

Franco (aka OrsoCurioso)