<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-340233044008832767</id><updated>2024-09-24T19:04:28.877+02:00</updated><category term="SQL Server 2012"/><category term="Sql Server 2008"/><category term="Sql Server 2008 R2"/><category term="Performance tuning"/><category term="SQL Server 2005"/><category term="Sql Server 2008 - SQL Server Denali"/><category term="Conferenze It"/><category term="Execution Plan"/><category term="SQL Server 2012 RC0"/><category term="SQL Server 2014 CTP1"/><category term="SQL Server Denali"/><category term="T-SQL"/><category term="Hekaton"/><category term="Performance"/><category term="SQL Server 2014"/><category term="SQL Server 2014 novità"/><category term="Troubleshooting"/><category term="Business Intelligence"/><category term="In Memory Oltp"/><category term="In-Memory Optimized Tables"/><category term="Rebuild Indexes"/><category term="SQL Server 2014 What&#39;s new"/><category term="Analisi su Sql Server"/><category term="DQS"/><category term="Data Pages"/><category term="Data Quality Services"/><category term="Extended Events"/><category term="Ram"/><category term="SqlSaturday"/><category term="Asyncronous File Target"/><category term="Backup"/><category term="Buffer Pool"/><category term="Common table expression"/><category term="Database Maintenance"/><category term="DeadLock Monitoring"/><category term="Dirty Pages"/><category term="Initial Snapshot"/><category term="Isolation level"/><category term="Jobs"/><category term="Latch Free"/><category term="Latch Lock Free"/><category term="LocalDb"/><category term="Lock"/><category term="Modellazione"/><category term="Natively compiled stored procedures"/><category term="Reorganize Indexes"/><category term="Replication"/><category term="Restore"/><category term="SQL Profiling"/><category term="SQL Server 2014 CTP2"/><category term="SQL Server 2014 Hash Index"/><category term="SQL Server 2014 In-Memory Technology"/><category term="SQL Server Express"/><category term="Set Based"/><category term="Sicurezza"/><category term="Sql Injection"/><category term="Sql Server 2014 Range Index"/><category term="Sql Server Extended Events"/><category term="T-SQL Error Handling"/><category term="Table"/><category term="Tracing"/><category term="Transactional Replication"/><category term="Transactions"/><category term="datapage"/><category term="monitoring with extended events"/><title type='text'>SQL Server Tips &amp;amp; Tricks</title><subtitle type='html'>Piccoli appunti sparsi relativi alla piattaforma SQL Server !!!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>73</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-7375085113837966172</id><published>2013-12-05T23:00:00.000+01:00</published><updated>2013-12-06T08:58:01.311+01:00</updated><title type='text'>SQL Server 2014 : Updatable Clustered Columnstore Index</title><content type='html'>Tra le svariate novità che introdurrà Sql Server 2014 vi sono anche i &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/gg492088(v=sql.120).aspx&quot; target=&quot;_blank&quot;&gt;Clustered ColumnStored Index&lt;/a&gt;.&lt;br /&gt;
Sono uno strumento molto potente qualora si abbia la necessita di applicare aggregazioni e raggruppamenti su tabelle dei fatti molto grosse.&lt;br /&gt;
I&amp;nbsp;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/gg492088.aspx#Described&quot; target=&quot;_blank&quot;&gt;Columnstore Index&lt;/a&gt;&amp;nbsp;introdotti da SQL Server 2012&amp;nbsp;(ne ho&amp;nbsp;parlato in un vecchio &lt;a href=&quot;http://tipsandtrickssqlserver.blogspot.it/2012/11/sql-server-2012-column-store-index.html&quot; target=&quot;_blank&quot;&gt;post)&lt;/a&gt;&amp;nbsp;impedivano&amp;nbsp;di aggiornare la&amp;nbsp;tabella su cui erano stati creati mentre i&amp;nbsp;Clustered ColumnStored Index non hanno più questa limitazione.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Per utilizzare i nuovi Clustered Columnstore Index è necessario che l&#39;intera tabella sia&amp;nbsp;convertita da Rowstore (Heap o Clustered che sia)&amp;nbsp;a Columnstore.&lt;br /&gt;
Per eseguire questa operazione dobbiamo rimuovere tutti gli indici dalla tabella ed eseguire il comando :&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/gg492153(v=sql.120).aspx&quot; target=&quot;_blank&quot;&gt;Create Clustered Columnstore Index&lt;/a&gt; IdxName On MyTable.&lt;br /&gt;
Di fatto la tabella stessa è il Clustered ColumnStore Index.&lt;br /&gt;
&lt;br /&gt;
La modalità di salvataggio dei dati in&amp;nbsp;ColumnStore mode prevede che ogni colonna della tabella&amp;nbsp;sia salvata in modalità compressa&amp;nbsp;in una struttura fisicamente separata dalle altre colonne della tabella stessa.&lt;br /&gt;
Questa struttura fisica da un enorme vantaggio a quelle operazioni di aggregazione e&amp;nbsp;raggruppamento&amp;nbsp;su tabelle dei fatti di grosse&amp;nbsp;dimensioni; separando fisicamente le colonne tra loro evito letture inutili che aumenterebbero la quantità di I/O necessario per reperire tutti i dati. Inoltre i dati stessi di ogni colonna&amp;nbsp;sono salvati in un formato compresso. Ciò significa che anche in termini di allocazione di spazio su disco ottengo notevoli benefici(anche in termini di performance visto&amp;nbsp;che riduco ulteriormente l&#39;I/O necessario).&lt;br /&gt;
&lt;br /&gt;
Vediamo un pò di terminologia:&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Rowgroup&lt;/strong&gt; &lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Gruppo di righe salvate in modalità compressa e in formato ColumnStore.&lt;/li&gt;
&lt;/ol&gt;
&lt;strong&gt;Column Segment&lt;/strong&gt; &lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Gruppo di valori di una sola colonna salvati in modo compresso e contenuti nella medesima struttura.&lt;/li&gt;
&lt;li&gt;Ogni colonna è salvata in strutture separate dalle altre e tutte sono suddivise in segmenti.&lt;/li&gt;
&lt;li&gt;Ogni RowGroup contiene un Column Segment di tutte le colonne nella tabella.&lt;/li&gt;
&lt;/ol&gt;
&lt;strong&gt;Rowstore&lt;/strong&gt;&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;I dati sono salvati su righe e colonne &quot;contenute fisicamemente nella medesima struttura&quot;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Area temporanea dove vengono inserite le nuove righe in attesa d&#39;essere aggiunte al columnstore.&lt;/li&gt;
&lt;/ol&gt;
&lt;strong&gt;DeltaStore&lt;/strong&gt; &lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Il DeltaStore è&amp;nbsp;ciò che rende&amp;nbsp;i Clustered Columnstore Index editabili....&lt;/li&gt;
&lt;li&gt;E&#39;&amp;nbsp;composto da&amp;nbsp;Rowstore contenenti le righe che nel tempo andrò ad inserire nella tabella.&lt;/li&gt;
&lt;/ol&gt;
Vediamo come funzionano in scrittura i Clustered ColumStore Index&lt;br /&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;Esecuzione di Insert&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;
Quando eseguiamo un inserimento in una tabella ColumnStore la nuova riga viene salvata nel RowStore aperto nel DeltaStore. Se non esistono RowStore ne viene creato ed aperto&amp;nbsp;uno. Solo quando il Rowstore raggiunge la soglia di 2^20 (1.048.576 record) verrà chiuso. A questo punto un background process chiamato &quot;Tuple-Mover&quot;&amp;nbsp;cerca nel&amp;nbsp;DeltaStore i RowStore chiusi, li comprime e li sposta nel ColumnStore.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjICS1rbU7XHSVXtUGOLa7C3WPgS3zbbleG7I88X1tCH4c4qZiKAIAoztFj80OFJL1DgU7KZ4zYl0mmzljk54mC3PlcsSCUgB1jkz90nx4QVpnHQdzzC0VWYU0T89XVn-rup7-Q-2_p9f4A/s1600/1.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;284&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjICS1rbU7XHSVXtUGOLa7C3WPgS3zbbleG7I88X1tCH4c4qZiKAIAoztFj80OFJL1DgU7KZ4zYl0mmzljk54mC3PlcsSCUgB1jkz90nx4QVpnHQdzzC0VWYU0T89XVn-rup7-Q-2_p9f4A/s640/1.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;strong&gt;Esecuzione di Delete&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Se invece dobbiamo eliminare delle righe dalla tabella abbiamo 2 comportamenti distinti&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Se la riga è nel DeltaStore&amp;nbsp;verrà fisicamente eliminata.&lt;/li&gt;
&lt;li&gt;Se la riga è nel ColumnStore verrà marcata come&amp;nbsp;&quot;cancellata&quot; ma fisicamente rimarrà al suo posto. Sarà eliminata fisicamente solo&amp;nbsp;durante la Rebuild della tabella.&lt;/li&gt;
&lt;/ol&gt;
Vediamo&amp;nbsp;degli esempi.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;1. INSERT&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Creo un DB contenente una tabella con Clustered ColumnStore Index popolata con 100.000 Record&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Master
Go

Create Database TestClusteredColumnStore
Go

Use TestClusteredColumnStore
Go

Create table TabClusteredColumnStore 
( 
 id int identity,
 valore1 int, 
 valore2 int, 
 valore3 int, 
 valore4 int, 
 valore5 int, 
) 
Go

/***************************************************************************************
ATTENZIONE : questa operazione trasforma la tabella da HEAP(Rowstore) a ColumnStore
***************************************************************************************/
create clustered columnstore index idxClustColStore on TabClusteredColumnStore
Go

--Popolo la tabella con 100000 Record
;With Cte as (Select 1 Riga union All Select 1)
 ,Cte4 as (Select A.Riga From Cte A, Cte B )
 ,Cte16 as (Select A.Riga From Cte4 A, Cte4 B )
 ,Cte256 as (Select A.Riga From Cte16 A, Cte16 B )
 ,Cte65536 as (Select A.Riga From Cte256 A, Cte256 B )
 ,cteMolti as (Select A.Riga From Cte65536 A, Cte65536 B )
 ,Results as (Select Row_number() Over(Order By Riga) Riga From cteMolti)
Insert into TabClusteredColumnStore
Select Riga,Riga,Riga,Riga,Riga from Results Where Riga &amp;lt;= 100000
Go

&lt;/pre&gt;
Eseguiamo questa vista di sistema : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;--Ho un solo RowGroup aperto nel deltastore
select object_name(object_id)TabName
  ,* 
from sys.column_store_row_groups
Go
&lt;/pre&gt;
&lt;br /&gt;
La&amp;nbsp;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dn223749(v=sql.120).aspx&quot; target=&quot;_blank&quot;&gt;sys.column_store_row_groups&lt;/a&gt; è una vista di sistema che mi restituisce informazioni su ogni Clustered ColumnStore Index presente nel database.&lt;br /&gt;
&lt;br /&gt;
Il risultato è il seguente&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR1HKtKEzgHNLYzS_5GMZwUmkjhySBKjMb8IgqC97cycxoRB0T47ENUMF6443JvUL1-kVHLHsVbS7RtbUrlpjUHXBE4Ud4KhGRIu7kbnb2ODkHxBn-Z8on20F5X6F0owQPQGBVjcZWBc3C/s1600/2.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;124&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR1HKtKEzgHNLYzS_5GMZwUmkjhySBKjMb8IgqC97cycxoRB0T47ENUMF6443JvUL1-kVHLHsVbS7RtbUrlpjUHXBE4Ud4KhGRIu7kbnb2ODkHxBn-Z8on20F5X6F0owQPQGBVjcZWBc3C/s640/2.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Come vedete la tabella TabClusteredColumnStore ha un DeltaStore contenente un RowStore che a sua volta contiene 100.000 Record. Lo stato del RowStore è OPEN, quindi in grado di ricevere ulteriori record.&lt;br /&gt;
Provo adesso ad inserire abbastanza righe per raggiungere la soglia massima.&lt;br /&gt;
La soglia è 1048576 , quindi dato che ne ho già inserite 100000 devo aggiungerne altre 948576&amp;nbsp;+ 1 in modo da causare la chiusura del RowStore.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;--Arrivo alla soglia del Rowstore
;With Cte as (Select 1 Riga union All Select 1)
 ,Cte4 as (Select A.Riga From Cte A, Cte B )
 ,Cte16 as (Select A.Riga From Cte4 A, Cte4 B )
 ,Cte256 as (Select A.Riga From Cte16 A, Cte16 B )
 ,Cte65536 as (Select A.Riga From Cte256 A, Cte256 B )
 ,cteMolti as (Select A.Riga From Cte65536 A, Cte65536 B )
 ,Results as (Select Row_number() Over(Order By Riga) Riga Riga From cteMolti)
Insert into TabClusteredColumnStore
Select Riga,Riga,Riga,Riga,Riga from Results Where Riga &amp;lt;= 948577
Go
&lt;/pre&gt;
&lt;br /&gt;
Rieseguo la select di prima su&amp;nbsp;sys.column_store_row_groups.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMlqMplczPRB0N1S1QsMaPf-eSq98wQHRMklsK5flRnrELPtduGUHSu6VN9aJz3kOyg_b08QGN7b0cBozfPzP2lNuD0kxn1mhBnT9FIq9pnAlEIMvlNHiUhIUeomqlBXjmiHNCmxZMbq_M/s1600/3.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img height=&quot;156&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMlqMplczPRB0N1S1QsMaPf-eSq98wQHRMklsK5flRnrELPtduGUHSu6VN9aJz3kOyg_b08QGN7b0cBozfPzP2lNuD0kxn1mhBnT9FIq9pnAlEIMvlNHiUhIUeomqlBXjmiHNCmxZMbq_M/s640/3.PNG&quot; unselectable=&quot;on&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Come vedete il RowStore è stato chiuso e contiene 1048576 righe. Inoltre è stato creato un RowStore nuovo contenente una sola riga, inserita dall&#39;istruzione precedente.&lt;br /&gt;
Il Background process Tuple-Mover alla prima esecuzione troverà il RowStore in stato CLOSED e lo&amp;nbsp;inserirà&amp;nbsp;in modalità compressa&amp;nbsp;nel ColumnStore index.&lt;br /&gt;
&lt;br /&gt;
Rieseguo dopo qualche minuto la medesima query su&amp;nbsp;sys.column_store_row_groups.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRcwaGfvbaM1cBrUi4ZrsxCu23hga5EmOdgjXMcKRr-A7GF3XRmM4gWHCNkeK4Vam8pzZ_F2fuF9abzLXnwpHqNNEaqR9uRs6_GBtYsPMMt43PsWn1xngEAdytRdm2n4sjQrMC-MwL_lgW/s1600/4.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img height=&quot;136&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRcwaGfvbaM1cBrUi4ZrsxCu23hga5EmOdgjXMcKRr-A7GF3XRmM4gWHCNkeK4Vam8pzZ_F2fuF9abzLXnwpHqNNEaqR9uRs6_GBtYsPMMt43PsWn1xngEAdytRdm2n4sjQrMC-MwL_lgW/s640/4.PNG&quot; unselectable=&quot;on&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lo stato ora è COMPRESSED, il che significa che le righe sono state inserite nel Clustered ColumnStore Index dal Tuple-Mover.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;2. DELETE&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Cosa accade quando eseguo la delete di una riga già nel Clustered ColumnStore Index ?&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Delete From TabClusteredColumnStore Where id = 1
Go
&lt;/pre&gt;
&lt;br /&gt;
Come detto prima, se la riga è nel ColumnStore verrà marcata come eliminabile ma non verrà eliminata fisicamente dalla struttura.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTyAVntQtVHHay9FbY4tUTBtbEpYGcfvcscTal8P1toWTLIkz05gJG1Rps6knhSS5MeBvMY76dliNbNtselTHqJ2GKZrrCAr1ZsBjMk3Fdolr3AGOlETiY_BIQWwgokVbQhyz1FIYPe8NT/s1600/5.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img height=&quot;122&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTyAVntQtVHHay9FbY4tUTBtbEpYGcfvcscTal8P1toWTLIkz05gJG1Rps6knhSS5MeBvMY76dliNbNtselTHqJ2GKZrrCAr1ZsBjMk3Fdolr3AGOlETiY_BIQWwgokVbQhyz1FIYPe8NT/s640/5.PNG&quot; unselectable=&quot;on&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L&#39;eliminazione fisica delle righe dal ColumnStore verrà eseguita quando sarà effettuato il rebuild del Clustered ColumnStore Index.&lt;br /&gt;
&lt;br /&gt;
Cosa accade quando eseguo una Delete di una riga in RowStore in stato OPEN&amp;nbsp;nel DeltaStore ?&lt;br /&gt;
(La riga con id 1048577 è nel RowStore OPEN)&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Delete From TabClusteredColumnStore Where id = 1048577
Go
&lt;/pre&gt;
&lt;br /&gt;
Come detto prima se la riga è in un RowStore in stato OPEN nel DeltaStore allora verrà eliminata definitivamente.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-JhTAduJoIpjHDU7nUem5Y0OCI0Uf-_XgILRLuP31vfXDYpbCoalYeqLKlSOQvD0f6Wh9D0a7KKrJXt57-DaJ7aTstk9Ne6xdj4kIhP-g2ErzLqttcOmErN6gxzLlb4oJmyy4OdqJg3FN/s1600/6.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img height=&quot;126&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-JhTAduJoIpjHDU7nUem5Y0OCI0Uf-_XgILRLuP31vfXDYpbCoalYeqLKlSOQvD0f6Wh9D0a7KKrJXt57-DaJ7aTstk9Ne6xdj4kIhP-g2ErzLqttcOmErN6gxzLlb4oJmyy4OdqJg3FN/s640/6.PNG&quot; unselectable=&quot;on&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ed effettivamente viene eliminata, la colonna Total_Rows restituita dalla vista mi dice che ora le righe sono 0 (Nella esecuzione precedente mi dava 1 Riga per il RowStore in stato OPEN).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;3. Data Compression&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;
I dati di ColumnStore Index e di Clustered ColumnStore Index vengono salvati in modalità compressa. Per farci un&#39;idea del risparmio in termini di spazio e di I/O creo una tabelle esattamente uguale a TabClusteredColumnStore ma con la struttura standard a cui siamo abituati da anni e la popolo con lo stesso numero di righe&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Create table TabStandardRowStore 
( 
 id int identity primary key clustered, 
 valore1 int, 
 valore2 int, 
 valore3 int, 
 valore4 int, 
 valore5 int, 
) 

;With Cte as (Select 1 Riga union All Select 1)
 ,Cte4 as (Select A.Riga From Cte A, Cte B )
 ,Cte16 as (Select A.Riga From Cte4 A, Cte4 B )
 ,Cte256 as (Select A.Riga From Cte16 A, Cte16 B )
 ,Cte65536 as (Select A.Riga From Cte256 A, Cte256 B )
 ,cteMolti as (Select A.Riga From Cte65536 A, Cte65536 B )
 ,Results as (Select Row_number() Over(Order By Riga) Riga From cteMolti)
Insert into TabStandardRowStore
Select Riga,Riga,Riga,Riga,Riga from Results Where Riga &amp;lt;= 1048576
Go

&lt;/pre&gt;
&lt;br /&gt;
Vediamo quanto spazio abbiamo risparmiato&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Exec sp_spaceused &#39;TabClusteredColumnStore&#39;
Exec sp_spaceused &#39;TabStandardRowStore&#39;&lt;/pre&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5XnSbny2q7iLAFIEYEZlsfyE9hEjgnM81ehcuIB6FtkPItCB3TSzyVNbtuCPLuE6CTVwktR0qqAnZdwmT-Dluh2cOcaJlrPhQWJ2rHGlyVFUUyY5zdKMgHCOYSuDHDZXdYKWrG1SBuBaF/s1600/7.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;276&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5XnSbny2q7iLAFIEYEZlsfyE9hEjgnM81ehcuIB6FtkPItCB3TSzyVNbtuCPLuE6CTVwktR0qqAnZdwmT-Dluh2cOcaJlrPhQWJ2rHGlyVFUUyY5zdKMgHCOYSuDHDZXdYKWrG1SBuBaF/s640/7.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&amp;nbsp;&lt;/div&gt;
Il risparmio direi che è notevole, la tabella TabClusteredColumnStore alloca meno della metà dello spazio della sua gemella con la struttura tradizionale.&lt;br /&gt;
&lt;br /&gt;
In SQL Server 2014 inoltre è stato aggiunto un nuovo tipo di compressione&amp;nbsp;ancora più efficiente.&lt;br /&gt;
Lo applico alla tabella TabClusteredColumnStore &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Alter table TabClusteredColumnStore rebuild with(Data_compression = ColumnStore_Archive)
&lt;/pre&gt;
&lt;br /&gt;
Riverifico lo spazio allocato &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3PAtOOh7Q3xBePkMVKh1LOMCPc9pMPztvwzbMEhf15T7F2V2ahkMJEs2BY52olKJVuVtmTOOy0e6WWATHrQwhQzPtxXlzgte9USv_CIw8_sJYXmpQRjXQ3kxXL_a6OgfddQeklw_hmvo8/s1600/9.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3PAtOOh7Q3xBePkMVKh1LOMCPc9pMPztvwzbMEhf15T7F2V2ahkMJEs2BY52olKJVuVtmTOOy0e6WWATHrQwhQzPtxXlzgte9USv_CIw8_sJYXmpQRjXQ3kxXL_a6OgfddQeklw_hmvo8/s640/9.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
che&amp;nbsp;è ulteriormente calato.....&lt;br /&gt;
&lt;br /&gt;
Per maggiori info sulla compressione dei dati nei ColumnStore Index vi consiglio di leggere il blog di &lt;a href=&quot;http://www.nikoport.com/2013/07/20/clustered-columnstore-indexes-part-12-compression-dive/&quot; target=&quot;_blank&quot;&gt;Niko Nuegebauer&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
N.B. La rebuild ha ricostruito il Clustered ColumnStore Index e ha anche eliminato la riga eliminata precedentemente.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9E3M4FOzXYw4cM3weBEdkBgjVSux7YuvwoAxJ88XB44XnRLsAvKLr80Eh7FG_xQd-Ig-PJC8mkzF3jQgdXVvW41WSJEh8CzOWv64PFI3ewsyGTbDMgppTM0FKU-QKuDCXKUIRJ3i6gQK1/s1600/10.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9E3M4FOzXYw4cM3weBEdkBgjVSux7YuvwoAxJ88XB44XnRLsAvKLr80Eh7FG_xQd-Ig-PJC8mkzF3jQgdXVvW41WSJEh8CzOWv64PFI3ewsyGTbDMgppTM0FKU-QKuDCXKUIRJ3i6gQK1/s640/10.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/7375085113837966172/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/12/sql-server-2014-updatable-clustered.html#comment-form' title='3 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/7375085113837966172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/7375085113837966172'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/12/sql-server-2014-updatable-clustered.html' title='SQL Server 2014 : Updatable Clustered Columnstore Index'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjICS1rbU7XHSVXtUGOLa7C3WPgS3zbbleG7I88X1tCH4c4qZiKAIAoztFj80OFJL1DgU7KZ4zYl0mmzljk54mC3PlcsSCUgB1jkz90nx4QVpnHQdzzC0VWYU0T89XVn-rup7-Q-2_p9f4A/s72-c/1.PNG" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-8120504493536545223</id><published>2013-11-19T14:28:00.001+01:00</published><updated>2013-11-19T14:28:08.661+01:00</updated><title type='text'>SQL Server 2012 Cumultive Update 7</title><content type='html'>E&#39; uscita la CU7 di SQL Server 2012.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://support.microsoft.com/kb/2823247/en&quot; target=&quot;_blank&quot;&gt;Qui&lt;/a&gt; il link per il download.&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/8120504493536545223/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/11/sql-server-2012-cumultive-update-7.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8120504493536545223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8120504493536545223'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/11/sql-server-2012-cumultive-update-7.html' title='SQL Server 2012 Cumultive Update 7'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-2854339962819833648</id><published>2013-11-12T17:35:00.004+01:00</published><updated>2014-01-15T13:46:42.110+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Hekaton"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 CTP1"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 CTP2"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 Hash Index"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 In-Memory Technology"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 novità"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2014 Range Index"/><title type='text'>SQL Server 2014 Range Index Vs Hash Index</title><content type='html'>SQL Server 2014 Ctp2 rende disponibile oltre alle In-Memory table con Hash Index anche le In-Memory Table dotate di Range Index.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;La struttura di un Hash Index è assimilabile a questa&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRuDJAJqR9V6LBRk9pRSvXs5g5dug9LT-PY7ncq0x_G4ASJru5T43G-YJBoqPIfPmi-wr7stnk-A2NF5laUyxlCgEm0zq016eD9NiNR6X4P20ZnwhTEtqJrnESisu7dETy8P6kb1MhruGw/s1600/4.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;143&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRuDJAJqR9V6LBRk9pRSvXs5g5dug9LT-PY7ncq0x_G4ASJru5T43G-YJBoqPIfPmi-wr7stnk-A2NF5laUyxlCgEm0zq016eD9NiNR6X4P20ZnwhTEtqJrnESisu7dETy8P6kb1MhruGw/s400/4.PNG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Il suo funzionamento è spiegato molto bene a questo &lt;a href=&quot;http://sqlblog.com/blogs/kalen_delaney/archive/2013/06/05/hekaton-whitepaper.aspx&quot; target=&quot;_blank&quot;&gt;link&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Una delle limitazioni che abbiamo con l&#39;utilizzo di In-Memory table con indici Hash, ne ho parlato in questo &lt;a href=&quot;http://tipsandtrickssqlserver.blogspot.it/2013/06/sql-server-2014-ctp1-un-vero-in-memory.html&quot;&gt;post&lt;/a&gt;, è che per ciascun indice, dobbiamo necessariamente conoscere la cardinalità dei dati per poter definire la dimensione del Bucket_Count. In altre parole dobbiamo conoscere a priori quante righe conterrà&amp;nbsp;la tabella...&lt;br /&gt;
Un altro limite degli Hash index è che non consentono accessi in&amp;nbsp;Seek alla tabella&amp;nbsp;per ricerche basate su range di valori. Ciò significa che in questi casi l&#39;engine implementa una Scan della tabella intera.&lt;br /&gt;
&lt;br /&gt;
Qualora non si conosca la cardinalità dei dati o si&amp;nbsp;debbano effettuare ricerche basate su range di valori conviene utilizzare i Range index.&lt;br /&gt;
&lt;br /&gt;
Questa tipologia di oggetti ha una struttura a Bw-Tree (Buzz Word Tree).&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC4BfoQzOA23qvyVlQmIkU37fydakxTrZnK1rz-zoXvUpsHV9M96PiBy2xJx0EiSBjCPgNM2vs4bMCCfpPMUSiaRFWygihXaIMK-X412ZCEyAms6C-6A3Ywk2jFQJ3xoyENyKC3_uRH5Ib/s1600/1.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;215&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC4BfoQzOA23qvyVlQmIkU37fydakxTrZnK1rz-zoXvUpsHV9M96PiBy2xJx0EiSBjCPgNM2vs4bMCCfpPMUSiaRFWygihXaIMK-X412ZCEyAms6C-6A3Ywk2jFQJ3xoyENyKC3_uRH5Ib/s400/1.PNG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La struttura ricorda i B-Tree a cui siamo abituati, ma non lasciamoci trarre in inganno, sono differenti ed il loro funzionamento è ben spiegato&amp;nbsp;a questo &lt;a href=&quot;http://research.microsoft.com/apps/pubs/default.aspx?id=178758&quot; target=&quot;_blank&quot;&gt;link.&lt;/a&gt;&lt;br /&gt;
La struttura&amp;nbsp;del BW-Tree, così come quella degli Hash index è&amp;nbsp;totalmente in memoria RAM, il che da ad entrambi tipi un incredibile vantaggio in termini di performance rispetto alle tabelle tradizionali.&lt;br /&gt;
&lt;br /&gt;
Per creare In-Memory Table&amp;nbsp;basate su&amp;nbsp;Hash e/o Range Index&amp;nbsp;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms174979(v=sql.120).aspx&quot; target=&quot;_blank&quot;&gt;qui&lt;/a&gt; trovate tutte le info.&lt;br /&gt;
&lt;br /&gt;
Proviamo a creare 2 In-Memory table &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;USE MASTER
GO

CREATE DATABASE Hekaton_Test      
 ON PRIMARY(NAME = [PRIMARY],         
   FILENAME = &#39;C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\Hekaton_DiskBasedTable.mdf&#39;)    
,FILEGROUP [Hekaton_InMemory_FG] CONTAINS MEMORY_OPTIMIZED_DATA          
 (NAME = [Hekaton_InMemory_Dir],
  FILENAME = &#39;C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\In_Memory_Table&#39;) 
LOG ON (name = [Hekaton_log], FILENAME=&#39;C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\Hekaton_Test_log.ldf&#39;)   
Go

USE Hekaton_Test
GO

--In-Mem with Hash Index
CREATE TABLE Hash_MemoryTable 
( 
 id INT NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH(BUCKET_COUNT = 65536)  
 ,Nome VARCHAR(25) COLLATE Latin1_General_100_BIN2 not null
 ,Cognome VARCHAR(50) COLLATE Latin1_General_100_BIN2 not null
 ,Indirizzo VARCHAR(50) COLLATE Latin1_General_100_BIN2 
 INDEX inMemoryIdx NONCLUSTERED HASH (Cognome,Nome) WITH(BUCKET_COUNT = 35000)  
)WITH 
 (
  MEMORY_OPTIMIZED = ON
  ,DURABILITY = SCHEMA_AND_DATA
 );  
GO

--In-Mem with Range Index
CREATE TABLE Range_MemoryTable 
( 
 id INT NOT NULL PRIMARY KEY NONCLUSTERED
 ,Nome VARCHAR(25) COLLATE Latin1_General_100_BIN2 not null
 ,Cognome VARCHAR(50) COLLATE Latin1_General_100_BIN2 not null
 ,Indirizzo VARCHAR(50) COLLATE Latin1_General_100_BIN2 
 INDEX inMemoryIdx NONCLUSTERED(Cognome,Nome)  
)WITH 
 (
  MEMORY_OPTIMIZED = ON
  ,DURABILITY = SCHEMA_AND_DATA
 );  
GO

--Popolo entrambe le 5tabelle con 65536 Record
;WITH Cte AS(SELECT 1 Riga UNION ALL SELECT 1) 
 ,Cte4 as (SELECT A.Riga FROM Cte A, Cte B) 
 ,Cte16 as (SELECT A.Riga FROM Cte4 A, Cte4 B) 
 ,Cte256 as (SELECT A.Riga FROM Cte16 A, Cte16 B) 
 ,Cte65536 as (SELECT A.Riga FROM Cte256 A, Cte256 B) 
 ,Results as (SELECT ROW_NUMBER()OVER(ORDER BY A.Riga) Riga FROM Cte65536 A,Cte65536 B) 
INSERT INTO Hash_MemoryTable(id, Nome, Cognome, Indirizzo) 
SELECT Riga 
  , &#39;Nome &#39; + Cast(Riga as char(8))  
  , &#39;Cognome &#39; + Cast(Riga as char(8))      
  , &#39;Indirizzo &#39; + Cast(Riga as char(8))  
FROM Results WHERE Riga &amp;lt;= 65536
GO

;WITH Cte AS(SELECT 1 Riga UNION ALL SELECT 1) 
 ,Cte4 as (SELECT A.Riga FROM Cte A, Cte B) 
 ,Cte16 as (SELECT A.Riga FROM Cte4 A, Cte4 B) 
 ,Cte256 as (SELECT A.Riga FROM Cte16 A, Cte16 B) 
 ,Cte65536 as (SELECT A.Riga FROM Cte256 A, Cte256 B) 
 ,Results as (SELECT ROW_NUMBER()OVER(ORDER BY A.Riga) Riga FROM Cte65536 A,Cte65536 B) 
INSERT INTO Range_MemoryTable(id, Nome, Cognome, Indirizzo)  
SELECT Riga 
  , &#39;Nome &#39; + Cast(Riga as char(8))  
  , &#39;Cognome &#39; + Cast(Riga as char(8))      
  , &#39;Indirizzo &#39; + Cast(Riga as char(8))  
FROM Results WHERE Riga &amp;lt;= 65536
GO
&lt;/pre&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&amp;nbsp;&lt;/div&gt;
In entrambe le tabelle il campo id è Primary Key e nella Hash_MemoryTable è associato ad un indice Hash mentre nella Range_MemoryTable è creato come Range. Inoltre, su entrambe le tabelle è presente un indice sulle colonne Cognome e Nome.  &lt;br /&gt;
&lt;br /&gt;
Come si comportano le due tabelle in caso di ricerca puntuale ?  &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;--Seek diretta
SELECT * FROM Hash_MemoryTable WHERE id = 65000
Go
SELECT * FROM Range_MemoryTable WHERE id = 65000
Go
&lt;/pre&gt;
&lt;br /&gt;
Il piano d&#39;esecuzione per le query è il medesimo.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG6k2-Xky9tkMvb0RHV16v72ce_FGtG9O1TdIH47mIJMucEixbzAS8gv_E_LfEUXdHFLW0CJnPXv3a-ulvuutv8JKBOTqt1qBj9imhJ0WdzPxaavnHlof2yz7OsJBzEMmZwdQK0bToPLie/s1600/2.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG6k2-Xky9tkMvb0RHV16v72ce_FGtG9O1TdIH47mIJMucEixbzAS8gv_E_LfEUXdHFLW0CJnPXv3a-ulvuutv8JKBOTqt1qBj9imhJ0WdzPxaavnHlof2yz7OsJBzEMmZwdQK0bToPLie/s320/2.PNG&quot; width=&quot;313&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pur non essendo dei contatori particolarmente significativi guardiamo i &quot;Query cost (Relative to the batch)&quot; che&amp;nbsp;&amp;nbsp;danno l&#39;idea del peso di ciascuna query nel batch...&lt;br /&gt;
&lt;br /&gt;
Il piano d&#39;esecuzione per la ricerca nella Hash_MemoryTable è estremamente performante nelle ricerche puntuali. Questo perché l&#39;indice Hash, che di fatto è un array di puntatori,&amp;nbsp;contiene l&#39;indirizzo della riga. La query&amp;nbsp;filtra direttamente sulla colonna di PK&amp;nbsp;Id = 65000, quindi sul valore 65000 viene applicata una funzione di hash che restituisce il bucket contenente l&#39;indirizzo della riga nell&#39;array.&lt;br /&gt;
&lt;br /&gt;
La query sulla Range_MemoryTable, a parità di piano d&#39;esecuzione, è meno performante dato che l&#39;accesso alla riga selezionata&amp;nbsp;è fatto seguendo l&#39;indice Bw-Tree.&lt;br /&gt;
&lt;br /&gt;
Cosa accade invece se modifico le condizioni di ricerca?&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;SELECT * FROM Hash_MemoryTable WHERE id &amp;gt;= 65000
Go
SELECT * FROM Range_MemoryTable WHERE id &amp;gt;= 65000
Go
&lt;/pre&gt;
&lt;br /&gt;
I piani d&#39;esecuzione in questo caso sono differenti...&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4BdMPPbHkw0l8QBZvNIn4YfBImyayeo85K3djc1sD7fNGD1uN-raB10OFfA2YAXOwTRBDdzwK_zT9h4mBOL_0dpcxtii86Lpz3VqwenovDm0LTN91aIu5W5jlh8qNNwA1pXlzq7SDt9Up/s1600/3.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;306&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4BdMPPbHkw0l8QBZvNIn4YfBImyayeo85K3djc1sD7fNGD1uN-raB10OFfA2YAXOwTRBDdzwK_zT9h4mBOL_0dpcxtii86Lpz3VqwenovDm0LTN91aIu5W5jlh8qNNwA1pXlzq7SDt9Up/s320/3.PNG&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La ricerca su Hash_MemoryTable è decisamente la più pesante, per sua natura la struttura di un Hash index non consente l&#39;uso del Seek in questi tipi di ricerche.&lt;br /&gt;
Il Range index, invece, utilizza un Seek risultando molto più performante. &lt;br /&gt;
Dopotutto è un Bw-Tree, quindi le ricerche di questo tipo sono il suo pane....&lt;br /&gt;
&lt;br /&gt;
Quale tipo&amp;nbsp;indice dunque è il migliore ?&lt;br /&gt;
Bhe... Dipende da cosa dobbiamo fare....&lt;br /&gt;
Per ricerche dirette l&#39;Hash Index è la soluzione più performante.&lt;br /&gt;
Per ricerche su range di valori il Range Index è quello che fa per noi.&lt;br /&gt;
&lt;br /&gt;
Dato che le In-Memory table possono avere fino ad un max di 8 Index possiamo creare delle strutture ibride che sfruttino sia gli indici Hash che i Range.&lt;br /&gt;
Sulle colonne che saranno accedute in modo diretto (Where id = 65000)&amp;nbsp;potrei creare un indice Hash, per le colonne su cui effettuo ricerche di tipo range (Where id &amp;gt;= 65000)&amp;nbsp;posso creare un Range Index.&lt;br /&gt;
&lt;br /&gt;
Un vantaggio comune ad entrambi i tipi di indici, dato che puntano alla riga nella sua interezza, è che l&#39;engine&amp;nbsp;non ha più la necessità di effettuare Key o Rid lookup.&lt;br /&gt;
&lt;br /&gt;
Creo una tabella tradizionale e la popolo con le solite 65536 righe&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;CREATE TABLE DiskTable  
( 
 id INT NOT NULL PRIMARY KEY CLUSTERED
 ,Nome VARCHAR(25) COLLATE Latin1_General_100_BIN2 not null
 ,Cognome VARCHAR(50) COLLATE Latin1_General_100_BIN2 not null
 ,Indirizzo VARCHAR(50) COLLATE Latin1_General_100_BIN2 
 INDEX DiskIdx NONCLUSTERED (Cognome,Nome) 
)
GO

;WITH Cte AS(SELECT 1 Riga UNION ALL SELECT 1) 
 ,Cte4 as (SELECT A.Riga FROM Cte A, Cte B) 
 ,Cte16 as (SELECT A.Riga FROM Cte4 A, Cte4 B) 
 ,Cte256 as (SELECT A.Riga FROM Cte16 A, Cte16 B) 
 ,Cte65536 as (SELECT A.Riga FROM Cte256 A, Cte256 B) 
 ,Results as (SELECT ROW_NUMBER()OVER(ORDER BY A.Riga) Riga FROM Cte65536 A,Cte65536 B) 
INSERT INTO DiskTable(id, Nome, Cognome, Indirizzo)  
SELECT Riga 
  , &#39;Nome &#39; + Cast(Riga as char(8))  
  , &#39;Cognome &#39; + Cast(Riga as char(8))      
  , &#39;Indirizzo &#39; + Cast(Riga as char(8))  
FROM Results WHERE Riga &amp;lt;= 65536
GO
&lt;/pre&gt;
&lt;br /&gt;
Come vedete la tabella ha la medesima struttura delle In-Memory create precedentemente e le stesse colonne indicizzate.&lt;br /&gt;
Ovviamente in termini di performance è molto più lenta delle In-Memory table ma non solo, ha un&#39;ulteriore handicap che è la struttura dei B-Tree tradizionali.&lt;br /&gt;
Le datapages&amp;nbsp;che compongono un index non clustered&amp;nbsp;cosa contengono ? &lt;br /&gt;
Contengono i valori&amp;nbsp;delle colonne su cui ho creato l&#39;indice ed eventualmente:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Se la tabella è dotata di chiave clustered il valore della chiave clustered stessa per la riga&lt;/li&gt;
&lt;li&gt;Se la tabella è in Heap&amp;nbsp;lo&amp;nbsp;Heap Rid&amp;nbsp;della riga&lt;/li&gt;
&lt;/ol&gt;
Cosa accade quindi se la query richiede altre colonne&amp;nbsp;oltre a quelle&amp;nbsp;contenute nell&#39;indice ?&lt;br /&gt;
&lt;br /&gt;
Prendiamo queste Select che richiedono tutte le colonne che compongono la tabella.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;SELECT * FROM DiskTable WHERE Cognome = &#39;Cognome 65000&#39; And Nome = &#39;Nome 65000&#39;
GO
SELECT * FROM Hash_MemoryTable WHERE Cognome = &#39;Cognome 65000&#39; And Nome = &#39;Nome 65000&#39;
GO
SELECT * FROM Range_MemoryTable WHERE Cognome = &#39;Cognome 65000&#39; And Nome = &#39;Nome 65000&#39;
GO
&lt;/pre&gt;
&lt;br /&gt;
Questi sono i piani d&#39;esecuzione generati dall&#39;engine&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkM257aH58d9Xe-gtV7qh4aukHLUTn73he3Ft821o8D6xekrtcNZfclCdvvQTL9udaYkauL2B1TyreHnZYG26-g5GGCJ8KlQYgM1OIWkk3wE7q_KYbayIL9MZKW2CacRiQULZ7-G0MeGav/s1600/5.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;303&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkM257aH58d9Xe-gtV7qh4aukHLUTn73he3Ft821o8D6xekrtcNZfclCdvvQTL9udaYkauL2B1TyreHnZYG26-g5GGCJ8KlQYgM1OIWkk3wE7q_KYbayIL9MZKW2CacRiQULZ7-G0MeGav/s320/5.PNG&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Accade che l&#39;engine è costretto ad implementare un Key LookUp se la tabella è clustered oppure un RID LookUp se la tabella è Heap per reperire anche i valori delle colonne non presenti nell&#39;indice.&lt;br /&gt;
Questi surplus di lavoro, sono comunque accessi ad altre strutture, diminuiscono le performance aumentando le risorse in uso ed i tempi di attesa.&lt;br /&gt;
Le select sulle In-Memory table non richiedono l&#39;operatore di Key Lookup dato che gli indici, sia Hash che Range (seppur nel leaf level),&amp;nbsp;hanno sempre disponibile il puntatore all&#39;intera riga. La select sulla DiskTable invece è costretta ad utilizzare un Key LookUp per reperire le colonne richieste.&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/2854339962819833648/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/11/sql-server-2014-range-index-vs-hash.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/2854339962819833648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/2854339962819833648'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/11/sql-server-2014-range-index-vs-hash.html' title='SQL Server 2014 Range Index Vs Hash Index'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRuDJAJqR9V6LBRk9pRSvXs5g5dug9LT-PY7ncq0x_G4ASJru5T43G-YJBoqPIfPmi-wr7stnk-A2NF5laUyxlCgEm0zq016eD9NiNR6X4P20ZnwhTEtqJrnESisu7dETy8P6kb1MhruGw/s72-c/4.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-5765887295580916399</id><published>2013-11-12T12:21:00.000+01:00</published><updated>2013-11-12T12:29:47.100+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Conferenze It"/><category scheme="http://www.blogger.com/atom/ns#" term="SqlSaturday"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL Error Handling"/><title type='text'>SQL Saturday 257 Session Download</title><content type='html'>Ciao,&lt;br /&gt;
&lt;a href=&quot;http://www.sqlsaturday.com/viewsession.aspx?sat=257&amp;amp;sessionid=17320&quot; target=&quot;_blank&quot;&gt;Qui&lt;/a&gt; potete scaricare le slide e le demo della sessione sulla gestione degli errori nel codice T-SQL che ho tenuto&amp;nbsp;Sabato 9/11/2013&amp;nbsp;al SQL Saturday 260 in Microsoft a Milano....&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/5765887295580916399/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/11/sql-saturday-257-session-download.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/5765887295580916399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/5765887295580916399'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/11/sql-saturday-257-session-download.html' title='SQL Saturday 257 Session Download'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-5564197664334518360</id><published>2013-10-17T15:56:00.000+02:00</published><updated>2013-10-17T15:56:36.499+02:00</updated><title type='text'>SQL Server 2014 CTP2 disponibile.</title><content type='html'>E&#39; uscito SQL Server 2014 Ctp2 e &lt;a href=&quot;http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx&quot; target=&quot;_blank&quot;&gt;qui&lt;/a&gt; potete farne il download !!!&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dn169381(v=sql.15).aspx&quot; target=&quot;_blank&quot;&gt;Qui&lt;/a&gt; trovate le release notes...&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/5564197664334518360/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/10/sql-server-2014-ctp2-disponibile.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/5564197664334518360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/5564197664334518360'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/10/sql-server-2014-ctp2-disponibile.html' title='SQL Server 2014 CTP2 disponibile.'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-1526597195274902669</id><published>2013-10-11T12:45:00.000+02:00</published><updated>2013-10-14T16:22:37.117+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Asyncronous File Target"/><category scheme="http://www.blogger.com/atom/ns#" term="monitoring with extended events"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server Extended Events"/><category scheme="http://www.blogger.com/atom/ns#" term="Tracing"/><title type='text'>Extended Events : Leggere il contenuto del file .xel</title><content type='html'>Come è possibile leggere il contenuto di un trace&amp;nbsp;su&amp;nbsp;file .Xel&amp;nbsp;prodotto dagli Extended Events di SQL Server 2012 ?&lt;br /&gt;
Utilizzando il T-SQL ed un poco di sano XML !! ;-)&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Facciamo un esempio.&lt;br /&gt;
&lt;br /&gt;
Creo una sessione denominata [MySession] il cui target è il file E:\MySession.xel&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;USE MASTER
GO

CREATE EVENT SESSION [MySession] ON SERVER 
ADD EVENT sqlserver.query_post_execution_showplan
(
    ACTION
  (
   sqlserver.client_app_name
   ,sqlserver.client_hostname
   ,sqlserver.nt_username
   ,sqlserver.sql_text
  )
),
ADD EVENT sqlserver.sql_statement_completed
(
    ACTION
  (
   sqlserver.client_app_name
   ,sqlserver.client_hostname
   ,sqlserver.nt_username
   ,sqlserver.sql_text
  )
)
ADD TARGET package0.asynchronous_file_target
 (
  SET filename=N&#39;E:\MySession.xel&#39;
 )
WITH (STARTUP_STATE=ON)
GO

ALTER EVENT SESSION [MySession] ON SERVER STATE=START
GO

&lt;/pre&gt;
Il file .xel prodotto dalla trace ha questa struttura&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp55u_r9hU_Bv4YzwaKdUT2tMF3CdKtdLoERJlx3Qsy4hwfZCYhUFEww3webdrNG-i1AtVgGJIonP1OmNdpXDcHqAt_QyeJLk3_lhFuOO31zI8p_5Eu1BZGb9QHGKbfOmNjCkbS-SzKA53/s1600/2.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp55u_r9hU_Bv4YzwaKdUT2tMF3CdKtdLoERJlx3Qsy4hwfZCYhUFEww3webdrNG-i1AtVgGJIonP1OmNdpXDcHqAt_QyeJLk3_lhFuOO31zI8p_5Eu1BZGb9QHGKbfOmNjCkbS-SzKA53/s400/2.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dato che il file è&amp;nbsp;umanamente illeggibile&amp;nbsp;possiamo consultarlo:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Utilizzando l&#39;interfaccia grafica&lt;/li&gt;
&lt;li&gt;Utilizzando T-SQL e XQuery&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
Se scelgo la prima opzione posso usufruire di un&#39;interfaccia come la seguente dove nella parte superiore della finestra ho l&#39;elenco degli eventi, nella parte inferiore il dettaglio del singolo evento selezionato.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPjv0rsA3bfC_lLA-xeQqf0J_0hw_KMHr8Z3LwrQD7puwbIgGkvCcoB3mxzfsxpy5Si7E7zTmpBLQv8Nl71JIm-ap_EwQvd90ADQlyMBR_OVgjQe2TqOOCpqIc1ZX7aY_rXKpm49jRXQa9/s1600/1.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPjv0rsA3bfC_lLA-xeQqf0J_0hw_KMHr8Z3LwrQD7puwbIgGkvCcoB3mxzfsxpy5Si7E7zTmpBLQv8Nl71JIm-ap_EwQvd90ADQlyMBR_OVgjQe2TqOOCpqIc1ZX7aY_rXKpm49jRXQa9/s400/1.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Se però il contenuto della trace è molto grosso e ho necessità di effettuare filtri, ricerche e aggregazioni forse mi conviene scegliere la strada del T-SQL utilizzando la dmv &lt;a href=&quot;http://technet.microsoft.com/en-US/library/cc280743.aspx&quot; target=&quot;_blank&quot;&gt;sys.fn_xe_file_target_read_file&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;SELECT 
    CAST(event_data AS XML) AS event_data 
 FROM 
    sys.fn_xe_file_target_read_file(&#39;E:\MySession*.xel&#39;, NULL, NULL, NULL) 
&lt;/pre&gt;
&lt;br /&gt;
Il carattere &quot;*&quot; nel nome del file indica alla dmv di leggere tutti i file xel denominati MySession presenti nella cartella. (Nella configurazione della session potremmo aver configurato anche il file rollover....)&lt;br /&gt;
&lt;br /&gt;
La dmv trasforma il/i file da incomprensibili a quasi comprensibili.&lt;br /&gt;
Per ogni evento ne reperisce l&#39;intero set di dati sottoforma di XML.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimSTWn2E2GpokEh6hZmtWe1ud0OKAh0FP4LdJInSH0Cce6qQgU9T8r6lOjSoOWvfgXifrVT9DA6TyX08IStIrXv2Oj6AAUttKqzGj7RZlPdmYkztmuamqOrsJSSmQx5QM3lp4AA53JyFLL/s1600/3.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimSTWn2E2GpokEh6hZmtWe1ud0OKAh0FP4LdJInSH0Cce6qQgU9T8r6lOjSoOWvfgXifrVT9DA6TyX08IStIrXv2Oj6AAUttKqzGj7RZlPdmYkztmuamqOrsJSSmQx5QM3lp4AA53JyFLL/s400/3.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ogni riga rappresenta un evento la cui struttura è indicativamente questa.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7XPhjgBTYte3RVlDmSlsCOg0ZaeLBpC6mhBHtrqb9WvBNKeVAYQ6_Js6v9qCjDIVsmOoXX20dx8BDP3vHDdn12ZTSiABrq7q5e4AJ-d2ZcHBK5KF7mhQDt088bQ0IdK3mv0eFCNW6hSUN/s1600/4.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7XPhjgBTYte3RVlDmSlsCOg0ZaeLBpC6mhBHtrqb9WvBNKeVAYQ6_Js6v9qCjDIVsmOoXX20dx8BDP3vHDdn12ZTSiABrq7q5e4AJ-d2ZcHBK5KF7mhQDt088bQ0IdK3mv0eFCNW6hSUN/s400/4.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Il numero dei nodi associati all&#39;evento dipende dal numero di Action e Fields selezionati per l&#39;evento stesso....&lt;br /&gt;
&lt;br /&gt;
Per reperire tutti i dati di un evento a questo punto devo conoscerne il path ed&amp;nbsp;il tipo e creare una XQuery.&lt;br /&gt;
Esempio: &lt;br /&gt;
Per reperire il&#39;id del database all&#39;interno del quale s&#39;è verificato l&#39;esempio devo seguire il path &quot;./data[@name=&quot;source_database_id]&quot;.&lt;br /&gt;
Per reperirne il valore utilizzo il&amp;nbsp;metodo &lt;a href=&quot;http://technet.microsoft.com/en-US/library/ms178030.aspx&quot; target=&quot;_blank&quot;&gt;value&lt;/a&gt;&amp;nbsp;o il metodo &lt;a href=&quot;http://technet.microsoft.com/en-US/library/ms191474.aspx&quot; target=&quot;_blank&quot;&gt;query&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Dovrei quindi scrivere la query seguente:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;;WITH BaseXml AS --Leggo il file
( 
    SELECT 
        CAST(event_data AS XML) AS event_data 
    FROM 
        sys.fn_xe_file_target_read_file(&#39;E:\MySession*.xel&#39;, NULL, NULL, NULL) 
), 
XmlQuery AS --Leggo gli eventi
( 
 SELECT
  N.x.value(&#39;@name&#39;, &#39;varchar(250)&#39;) event_name
  ,N.x.value(&#39;@timestamp&#39;, &#39;datetime&#39;) event_time
  ,event_data 
    FROM 
        BaseXml    
    CROSS APPLY 
        event_data.nodes(&#39;/event&#39;) N(x) 
)
SELECT Row_number()Over(Order By event_time) Sequence
  ,event_time UTC
  ,dateadd(minute, datepart(TZoffset, sysdatetimeoffset()),event_time) event_time
  ,event_name
  ,event_data.value(&#39;(/event/action[@name=&#39;&#39;client_app_name&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [client_app_name],
  event_data.value(&#39;(/event/action[@name=&#39;&#39;client_hostname&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [client_hostname],
  event_data.value(&#39;(/event/action[@name=&#39;&#39;cpu_id&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [cpu_id],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;cpu_time&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [cpu_time],
  event_data.value(&#39;(/event/action[@name=&#39;&#39;database_id&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [database_id],
  event_data.value(&#39;(/event/action[@name=&#39;&#39;database_name&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [database_name],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;database_name&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [database_name],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;duration&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [duration],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;estimated_cost&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [estimated_cost],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;estimated_rows&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [estimated_rows],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;last_row_count&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [last_row_count],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;line_number&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [line_number],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;logical_reads&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [logical_reads],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;nest_level&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [nest_level],
  event_data.value(&#39;(/event/action[@name=&#39;&#39;nt_username&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [nt_username],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;object_id&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [object_id],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;object_name&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [object_name],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;object_type&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [object_type],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;offset&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [offset],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;offset_end&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [offset_end],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;parameterized_plan_handle&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [parameterized_plan_handle],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;physical_reads&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [physical_reads],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;row_count&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [row_count],
  event_data.query(&#39;(/event/data[@name=&#39;&#39;showplan_xml&#39;&#39;]/value/*)[1]&#39;) AS [showplan_xml],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;source_database_id&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [source_database_id],
  event_data.value(&#39;(/event/action[@name=&#39;&#39;sql_text&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [sql_text],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;statement&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [statement],
  event_data.value(&#39;(/event/action[@name=&#39;&#39;username&#39;&#39;]/value)[1]&#39;,&#39;varchar(max)&#39;) AS [username],
  event_data.value(&#39;(/event/data[@name=&#39;&#39;writes&#39;&#39;]/value)[1]&#39;,&#39;bigint&#39;) AS [writes] 
FROM 
 XmlQuery
Order By 1
&lt;/pre&gt;
&lt;br /&gt;
Il problema è che devo conoscere esattamente il path di ogni dato necessario e compilare il codice a mano per ogni colonna che desidero reperire..... Non è proprio molto comodo.&lt;br /&gt;
&lt;br /&gt;
Fortunatamente, grazie al T-SQL dinamico posso risolvere questo inconveniente sfruttando CTE e tabelle temporanee per reperire, direttamente dall&#39;XML la struttura ed il path di ogni singolo nodo.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;DECLARE @FileName Varchar(256) = &#39;E:\MySession*.xel&#39;;

IF (OBJECT_ID(&#39;tempdb..#XQueryDef&#39;) IS NOT NULL) DROP TABLE #XQueryDef
IF (OBJECT_ID(&#39;tempdb..#XQuery&#39;) IS NOT NULL) DROP TABLE #XQuery

;WITH cteGetEventsFromFile AS --Leggo il file
( 
    SELECT 
        CAST(event_data AS XML) AS event_data 
    FROM 
        sys.fn_xe_file_target_read_file(@FileName, NULL, NULL, NULL) 
), 
cteGetEventsFather AS --Leggo gli eventi
( 
 SELECT
  N.x.value(&#39;@name&#39;, &#39;varchar(250)&#39;) event_name
  ,N.x.value(&#39;@timestamp&#39;, &#39;datetime&#39;) event_time
  ,event_data 
    FROM 
        cteGetEventsFromFile    
    CROSS APPLY 
        event_data.nodes(&#39;/event&#39;) N(x) 
)
,cteGetEventsFields AS --Leggo tutto ciò che riguarda ogni singolo evento
( 
    SELECT 
  L.event_name
        ,L.event_time
  ,N2.x.value(&#39;@name&#39;, &#39;varchar(100)&#39;) data_name
    FROM 
        cteGetEventsFather L 
    CROSS APPLY 
        L.event_data.nodes(&#39;event/*&#39;) N2(x) 
) 
,cteWhereToFind AS
(
SELECT 
 FL.event_name
 ,FL.event_time
 ,FL.data_name
 ,&#39;&#39;&#39;(/event/&#39;+ ISNULL(C.column_type, O.object_type) +&#39;[@name=&#39;&#39;&#39;&#39;&#39; + FL.data_name + &#39;&#39;&#39;&#39;&#39;]/value&#39; +IIF(C.type_name like &#39;%xml%&#39;,&#39;/*&#39;,&#39;&#39;) + &#39;)[1]&#39;&#39;&#39; + 
   + IIF(C.type_name IS NULL
      ,CASE WHEN O.Type_name like &#39;%string%&#39; THEN &#39;,&#39;&#39;varchar(max)&#39;&#39;&#39;
        WHEN  O.type_name like &#39;%int%&#39; THEN &#39;,&#39;&#39;bigint&#39;&#39;&#39;
        WHEN  O.type_name like &#39;%xml%&#39; THEN &#39;&#39;
        ELSE &#39;,&#39;&#39;varchar(max)&#39;&#39;&#39; END 

      ,CASE WHEN C.type_name like &#39;%string%&#39; THEN &#39;,&#39;&#39;varchar(max)&#39;&#39;&#39;
        WHEN C.type_name like &#39;%int%&#39; THEN &#39;,&#39;&#39;bigint&#39;&#39;&#39;
        WHEN C.type_name like &#39;%xml%&#39; THEN &#39;&#39;
        ELSE &#39;,&#39;&#39;varchar(max)&#39;&#39;&#39; END 
  ) WhereToFind
FROM cteGetEventsFields FL
 left Join sys.dm_xe_object_columns C
  On FL.data_name = C.name 
    and FL.event_name = object_name
 left Join sys.dm_xe_objects O
  On FL.data_name = O.name 
   and O.object_type = &#39;Action&#39;
)
SELECT DISTINCT * 
 INTO #XQueryDef
FROM cteWhereToFind

;WITH cteGetEventsFromFile AS --Leggo il file
( 
    SELECT 
        CAST(event_data AS XML) AS event_data 
    FROM 
        sys.fn_xe_file_target_read_file(@FileName, NULL, NULL, NULL) 
), 
cteGetEventsFather AS --Leggo gli eventi
( 
 SELECT
        N.x.value(&#39;@name&#39;, &#39;varchar(250)&#39;) event_name
  ,N.x.value(&#39;@timestamp&#39;, &#39;datetime&#39;) event_time
  ,event_data 
    FROM 
        cteGetEventsFromFile    
    CROSS APPLY 
        event_data.nodes(&#39;/event&#39;) N(x) 
)
SELECT * 
 INTO #XQuery
FROM cteGetEventsFather

DECLARE @strCmd VARCHAR(max)=&#39;SELECT Row_number()Over(Order By event_time) Sequence,dateadd(minute, datepart(TZoffset, sysdatetimeoffset()),event_time) event_time,event_name,&#39;
SELECT 
 @strCmd+= &#39;event_data.&#39; + IIF(data_name like &#39;%xml%&#39;,&#39;query&#39;,&#39;value&#39;) + &#39;(&#39; + WhereToFind + &#39;) AS &#39; + QUOTENAME(data_name) +  &#39;,&#39; + char(10)
FROM 
( 
 SELECT  DISTINCT  data_name, WhereToFind FROM #XQueryDef  
)A

SET @strCmd = reverse(stuff(reverse(Rtrim(@strCmd)), 1, 2, &#39;&#39;)) + &#39; FROM #XQuery Order By Sequence&#39;
EXEC(@strCmd)
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf5-v7TZ4qCxEbIL-huVpsW9JsIEb-mvEymlN53yGcSlSPnqnIImK8DHJIWGLsSuz9Z8fh44sVj_Xqyq1vxBbsa-ao4X8Pu2tMhI-I0Mh78dlD7CPSWd-Ncj3KPrzmQeeAlMEjFXjKCUwN/s1600/5.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf5-v7TZ4qCxEbIL-huVpsW9JsIEb-mvEymlN53yGcSlSPnqnIImK8DHJIWGLsSuz9Z8fh44sVj_Xqyq1vxBbsa-ao4X8Pu2tMhI-I0Mh78dlD7CPSWd-Ncj3KPrzmQeeAlMEjFXjKCUwN/s400/5.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Il risultato è una tabella&amp;nbsp;composta da&amp;nbsp;una colonna per ogni Action e&amp;nbsp;Fields e una riga per ogni evento intercettato e contenuto nell&#39;Xml.&lt;br /&gt;
A questo punto posso salvare il risultato in una&amp;nbsp;tabella temporanea su cui&amp;nbsp;fare, con codice T-SQL semplice tutte le query, le ricerche, le aggregazioni etc necessarie all&#39;analisi della trace.&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/1526597195274902669/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/10/extended-events-leggere-il-contenuto.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/1526597195274902669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/1526597195274902669'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/10/extended-events-leggere-il-contenuto.html' title='Extended Events : Leggere il contenuto del file .xel'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp55u_r9hU_Bv4YzwaKdUT2tMF3CdKtdLoERJlx3Qsy4hwfZCYhUFEww3webdrNG-i1AtVgGJIonP1OmNdpXDcHqAt_QyeJLk3_lhFuOO31zI8p_5Eu1BZGb9QHGKbfOmNjCkbS-SzKA53/s72-c/2.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-4782011784003808803</id><published>2013-10-09T11:24:00.000+02:00</published><updated>2013-11-12T12:19:41.784+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Conferenze It"/><category scheme="http://www.blogger.com/atom/ns#" term="Extended Events"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Profiling"/><category scheme="http://www.blogger.com/atom/ns#" term="SqlSaturday"/><title type='text'>SQL Saturday 260 Session Download</title><content type='html'>Ciao,&lt;br /&gt;
&lt;a href=&quot;http://www.sqlsaturday.com/viewsession.aspx?sat=260&amp;amp;sessionid=17328&quot; target=&quot;_blank&quot;&gt;Qui&lt;/a&gt; potete scaricare le slide e le demo della sessione sugli Extended Events&amp;nbsp;che ho tenuto ieri al SQL Saturday 260 in Microsoft a Milano....&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/4782011784003808803/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/10/sql-saturday-260-session-download.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/4782011784003808803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/4782011784003808803'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/10/sql-saturday-260-session-download.html' title='SQL Saturday 260 Session Download'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-3254622581924295387</id><published>2013-10-08T23:25:00.000+02:00</published><updated>2013-10-28T12:40:38.742+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Rebuild Indexes"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2008"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2008 R2"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2012"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><category scheme="http://www.blogger.com/atom/ns#" term="Table"/><title type='text'>Spostare una tabella da un FileGroup ad un altro</title><content type='html'>Mai avuto la necessità di spostare una tabella da un filegroup ad un altro ?&lt;br /&gt;
Mi è giusto capitato pochi giorni fa e &lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;per risolvere il problema mi sono creato una Stored Procedure che esegue :&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Salvataggio&amp;nbsp;metadati&amp;nbsp;di tutte le Fk della tabella&lt;/li&gt;
&lt;li&gt;Drop di tutte le Fk dalla tabella&lt;/li&gt;
&lt;li&gt;Disable di tutti gli indici&lt;/li&gt;
&lt;li&gt;Salvataggio&amp;nbsp;metadati&amp;nbsp;indice&amp;nbsp;clustered&lt;/li&gt;
&lt;li&gt;Drop Indice clustered dalla tabella&lt;/li&gt;
&lt;li&gt;Create indice clustered con i metadati salvati precedentemente sul nuovo filegroup&lt;/li&gt;
&lt;li&gt;Rebuild Indici non-clustered&lt;/li&gt;
&lt;li&gt;Create FK con i metadati salvati precedentemente&lt;/li&gt;
&lt;/ol&gt;
Ecco lo script :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;--N.B. MODIFICARE IL NOME DEL DB PRIMA DI USARE LO SCRIPT
Use TestMoveTable
Go
--N.B. MODIFICARE IL NOME DELLA TABELLA E DEL FILEGROUP
Declare @TabToMove varchar(128) = &#39;[dbo].[TableFK]&#39;
Declare @FileGroup varchar(128) = &#39;NEWFG&#39;

Declare @Disable_Index varchar(max) = &#39;Alter index ALL on &#39; + @TabToMove + &#39; Disable;&#39;
Declare @Drop_Clustered_Index varchar(max) = &#39;&#39;
Declare @Create_Clustered_Index varchar(max) = &#39;&#39;
Declare @Rebuild_NonClustered_Index varchar(max) = &#39;&#39;
Declare @Create_Fk varchar(max) = &#39;&#39;
Declare @Drop_Fk varchar(max) = &#39;&#39;
Select @Drop_Fk+= drop_command +&#39;;&#39; + char(13) + char(10) From 
(

 select 
  &#39;ALTER TABLE &#39;
  + QUOTENAME(Object_Name(FKC.Parent_object_id)) +  &#39; DROP CONSTRAINT &#39;
  + QUOTENAME(Object_name(FKC.constraint_object_id)) DROP_COMMAND
 from sys.foreign_key_columns FKC
  Inner Join sys.columns CP
   ON CP.object_id = FKC.parent_object_id 
    AND CP.column_id = FKC.parent_column_id
  Inner Join sys.columns RCP
   ON RCP.object_id = FKC.Referenced_object_id 
    AND RCP.column_id = FKC.Referenced_column_id
  Inner join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS Const
   ON Const.CONSTRAINT_NAME = Object_name(FKC.constraint_object_id)
 Where FKC.referenced_object_id = Object_ID(@TabToMove)
)Drop_Command


Select @Create_Fk+= create_command +&#39;;&#39; + char(13) + char(10) From 
(
 select 
  &#39;ALTER TABLE &#39;
  + QUOTENAME(Object_Name(FKC.Parent_object_id)) +  &#39; WITH CHECK ADD  CONSTRAINT &#39;
  + QUOTENAME(Object_name(FKC.constraint_object_id)) + &#39; FOREIGN KEY (&#39; 
  + QUOTENAME(CP.name) + &#39;) REFERENCES &#39; + QUOTENAME(Object_Name(FKC.Referenced_object_id)) 
  + &#39;(&#39; + QUOTENAME(RCP.name) + &#39;)&#39;
   + CASE WHEN Const.UPDATE_RULE = &#39;CASCADE&#39; THEN &#39; ON UPDATE CASCADE &#39; ELSE &#39;&#39; END
   + CASE WHEN Const.UPDATE_RULE = &#39;CASCADE&#39; THEN &#39; ON DELETE CASCADE &#39; ELSE &#39;&#39; END CREATE_COMMAND

 from sys.foreign_key_columns FKC
  Inner Join sys.columns CP
   ON CP.object_id = FKC.parent_object_id 
    AND CP.column_id = FKC.parent_column_id
  Inner Join sys.columns RCP
   ON RCP.object_id = FKC.Referenced_object_id 
    AND RCP.column_id = FKC.Referenced_column_id
  Inner join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS Const
   ON Const.CONSTRAINT_NAME = Object_name(FKC.constraint_object_id)
 Where FKC.referenced_object_id = Object_ID(@TabToMove)
)Create_Command

Select @Rebuild_NonClustered_Index = @Rebuild_NonClustered_Index + char(13) +char(10) + Rebuild_Index + &#39;;&#39; From
(
select &#39;Alter Index &#39;+ Quotename(i.name)  + &#39; on &#39; + @TabToMove + &#39; Rebuild&#39; 
   Rebuild_Index
from sys.indexes as i
  inner join sys.objects obj
    on i.object_id=obj.object_id
  inner join sys.schemas sch
    on obj.schema_id=sch.schema_id
  inner join sys.partitions part
    on i.object_id=part.object_id
     and i.index_id=part.index_id
  inner join sys.stats stats
    on i.object_id=stats.object_id
     and i.index_id=stats.stats_id
where i.object_id = object_id(@TabToMove)
 And I.type_desc = &#39;NONCLUSTERED&#39;
)A

Select @Drop_Clustered_Index = Drop_Index From
(
 select Case When is_primary_key = 1 Or is_unique_constraint = 1 Then &#39;Alter Table &#39; + @TabToMove + &#39; Drop constraint &#39; + Quotename(i.name) 
    else &#39;Drop index &#39; + Quotename(i.name) + &#39; on &#39; + @TabToMove  + &#39;;&#39;
   End  Drop_Index
 from sys.indexes as i
     inner join sys.objects obj
     on i.object_id=obj.object_id
     inner join sys.schemas sch
     on obj.schema_id=sch.schema_id
     inner join sys.partitions part
     on i.object_id=part.object_id
      and i.index_id=part.index_id
     inner join sys.stats stats
     on i.object_id=stats.object_id
      and i.index_id=stats.stats_id
 where i.object_id = object_id(@TabToMove)
  And I.type_desc = &#39;CLUSTERED&#39;
)A


Select @Create_Clustered_Index = Create_Index from
(
Select Case is_primary_key When 1 Then &#39;Alter Table &#39; + @TabToMove + &#39; Add constraint &#39; + index_name + &#39; Primary Key Clustered (&#39; + reverse(stuff(reverse(index_columns), 1, 1, &#39;&#39;)) + &#39;) on &#39; + @FileGroup + &#39;;&#39;
   else 
    Case is_unique_constraint when 1
     Then &#39;Alter Table &#39; + @TabToMove + &#39; Add constraint &#39; + index_name + &#39; Unique Clustered (&#39; + reverse(stuff(reverse(index_columns), 1, 1, &#39;&#39;)) + &#39;) on &#39; + @FileGroup + &#39;;&#39;
    else
     Case Is_unique When 1 
      Then &#39;Create Unique Clustered index &#39; + Quotename(index_name) + &#39; on &#39; + @TabToMove + &#39;(&#39; + reverse(stuff(reverse(index_columns), 1, 1, &#39;&#39;)) + &#39;) on &#39; + @FileGroup + &#39;;&#39;
     Else
      &#39;Create Clustered index &#39; + Quotename(index_name) + &#39; on &#39; + @TabToMove + &#39;(&#39; + reverse(stuff(reverse(index_columns), 1, 1, &#39;&#39;)) + &#39;) on &#39; + @FileGroup + &#39;;&#39;
     End
    End
  End Create_Index 
from
(
 select
 quotename(sch.name)+&#39;.&#39;+quotename(obj.name) [table_name],
 quotename(i.name) [index_name],
 i.type_desc,
 (
     select &#39;[&#39;+col.name+&#39;] &#39; 
          + Case is_descending_key When 1 then &#39; Desc,&#39; 
           Else &#39;Asc,&#39;
         End as [data()]
     from sys.index_columns as k
      inner join sys.columns col
          on k.object_id=col.object_id
           and k.column_id=col.column_id
     where k.object_id = i.object_id
      and k.index_id = i.index_id
      and k.index_id&amp;lt;&amp;gt;0
      and k.is_included_column&amp;lt;&amp;gt;1
      order by key_ordinal, k.column_id
     for xml path(&#39;&#39;)
 )
 as [index_columns],
 is_unique,
 is_primary_key,
 is_unique_constraint,
 fill_factor,
 is_padded
 from sys.indexes as i
     inner join sys.objects obj
     on i.object_id=obj.object_id
     inner join sys.schemas sch
     on obj.schema_id=sch.schema_id
     inner join sys.partitions part
     on i.object_id=part.object_id
      and i.index_id=part.index_id
     inner join sys.stats stats
     on i.object_id=stats.object_id
      and i.index_id=stats.stats_id
 where i.object_id = object_id(@TabToMove)
  And I.type_desc = &#39;CLUSTERED&#39; 
 )A
)B

Print @Drop_Fk
Print @Disable_Index
Print @Drop_Clustered_Index
Print @Create_Clustered_Index
Print @Rebuild_NonClustered_Index
Print @Create_Fk

&lt;/pre&gt;
&lt;br /&gt;
Lo script genera un&amp;nbsp; risultato simile a questo nella finestra Messages :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs7jsS67SZsxkw7ytpbtV9ng7RDV65lb18BNYKde8oSru13fFpvWVmrjdFnB95sBQfxV9WUobq7utJ7eRdGsO08Gy0vZM6rEWbcekSxieH2CaXQxC4gRc7egGsQq2bBvHzmedG1vFPVSBg/s1600/1.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs7jsS67SZsxkw7ytpbtV9ng7RDV65lb18BNYKde8oSru13fFpvWVmrjdFnB95sBQfxV9WUobq7utJ7eRdGsO08Gy0vZM6rEWbcekSxieH2CaXQxC4gRc7egGsQq2bBvHzmedG1vFPVSBg/s400/1.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Attenzione, non eseguire lo script su tabelle partizionate....&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/3254622581924295387/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/10/spostare-una-tabella-da-un-filegroup-ad.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/3254622581924295387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/3254622581924295387'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/10/spostare-una-tabella-da-un-filegroup-ad.html' title='Spostare una tabella da un FileGroup ad un altro'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs7jsS67SZsxkw7ytpbtV9ng7RDV65lb18BNYKde8oSru13fFpvWVmrjdFnB95sBQfxV9WUobq7utJ7eRdGsO08Gy0vZM6rEWbcekSxieH2CaXQxC4gRc7egGsQq2bBvHzmedG1vFPVSBg/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-5405291359259556305</id><published>2013-09-28T18:46:00.000+02:00</published><updated>2013-10-03T13:27:30.470+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Backup"/><category scheme="http://www.blogger.com/atom/ns#" term="Initial Snapshot"/><category scheme="http://www.blogger.com/atom/ns#" term="Replication"/><category scheme="http://www.blogger.com/atom/ns#" term="Restore"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2008"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2008 R2"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2012"/><category scheme="http://www.blogger.com/atom/ns#" term="Transactional Replication"/><title type='text'>Backup/Restore come Initial Snapshot di una replica transazionale</title><content type='html'>In certi scenari di replica, dove il DB da pubblicare è di grosse dimensioni, potrebbe essere conveniente configurare la/le sottoscrizioni partendo da un Backup\Restore anziché da un Initial Snapshot come prevede la procedure standard. &lt;br /&gt;
La creazione&amp;nbsp;dell&#39;Initial Snapshot&amp;nbsp;potrebbe essere molto lunga e consumare molte risorse che&amp;nbsp;in questo modo risparmiamo.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Vediamo un esempio per la creazione di una sottoscrizione da un backup....&lt;br /&gt;
&lt;br /&gt;
Voglio creare una sottoscrizione del Db DBPublisher del server Win12Node1 sul database DBSubscriber del server Win12Node2.&lt;br /&gt;
Su Win12node1 è già configurata la pubblicazione del DBPublisher denominata TestPub.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRfcFSSU_rSkWxp7uD2iBOBEB5PYu98dNTbVHPUYw9ZiJIDRpbVDE523qWtedfqrtThy0U2FEUjpc6pBMv7ukvihqcH6gJZ5HbWWqFNI2vBITBNJ1Ys94OquW2gSxOtFRtd3LzFBphefe-/s1600/1.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRfcFSSU_rSkWxp7uD2iBOBEB5PYu98dNTbVHPUYw9ZiJIDRpbVDE523qWtedfqrtThy0U2FEUjpc6pBMv7ukvihqcH6gJZ5HbWWqFNI2vBITBNJ1Ys94OquW2gSxOtFRtd3LzFBphefe-/s1600/1.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Step 1&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Sul&amp;nbsp;Publisher la prima cosa da fare è verificare se la pubblicazione in essere accetta sottoscrizioni inizializzate da backup. &lt;br /&gt;
Per verificare basta eseguire la &lt;a href=&quot;http://technet.microsoft.com/en-us/library/ms189782.aspx&quot; target=&quot;_blank&quot;&gt;sp_helppublication&lt;/a&gt;&amp;nbsp;e controllare il&amp;nbsp;setting allow_initialize_from_backup.&lt;br /&gt;
Questo setting può assumere 2 valori:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1.&amp;nbsp;&amp;nbsp; 0 non abilitato&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.&amp;nbsp;&amp;nbsp; 1 abilitato.&lt;br /&gt;
&lt;span style=&quot;color: maroon; font-family: Consolas; font-size: x-small;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: maroon; font-family: Consolas; font-size: x-small;&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: maroon; font-family: Consolas; font-size: x-small;&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: maroon; font-family: Consolas; font-size: x-small;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;--Da eseguire sul publisher
Exec sp_helppublication &#39;TestPub&#39;
GO&lt;/pre&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9LelAINK7vL5_CXtbk_1pGfMQevH0qqZSgbRiPc_O2KdT0eB6d0nlpKqIhHGzRyKaWJhq8kzwQifcTtavCBO4JUdJa68XgEZLZpcTCGKQFH-Ii381GNKTZZqNSfxXa9m1U6uBh6k47A4/s1600/2.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;64&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN9LelAINK7vL5_CXtbk_1pGfMQevH0qqZSgbRiPc_O2KdT0eB6d0nlpKqIhHGzRyKaWJhq8kzwQifcTtavCBO4JUdJa68XgEZLZpcTCGKQFH-Ii381GNKTZZqNSfxXa9m1U6uBh6k47A4/s640/2.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
Nel mio caso devo abilitare l&#39;inizializzazione da Backup, quindi devo eseguire la &lt;a href=&quot;http://technet.microsoft.com/en-us/library/ms188413.aspx&quot; target=&quot;_blank&quot;&gt;sp_changepublication&lt;/a&gt;.&lt;/div&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&amp;nbsp;&lt;/div&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;--Da eseguire sul publisher
Exec sp_changepublication @publication = &#39;TestPub&#39;
                      , @property = &#39;allow_initialize_from_backup&#39;
                      , @value  = &#39;true&#39;
GO&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Step 2&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;
Eseguire il &lt;a href=&quot;http://technet.microsoft.com/en-us/library/ms186858.aspx&quot; target=&quot;_blank&quot;&gt;Restore&lt;/a&gt; del DB sul server sottoscrittore, nel mio caso lo&amp;nbsp;chiamerò DBSubScriber partendo&amp;nbsp;dall&#39;ultimo set di&amp;nbsp;backup disponibile.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;N.B. &lt;/strong&gt;Se&amp;nbsp;l&#39;ultimo&amp;nbsp;backup disponibile&amp;nbsp;è più vecchio del periodo di Retention del distributor allora sarà necessario creare un nuovo set di &lt;a href=&quot;http://technet.microsoft.com/en-US/library/ms187510.aspx&quot; target=&quot;_blank&quot;&gt;backup&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;--Da eseguire sul subscriber
USE [master]
Go
Restore Database [DBSubScriber] From Disk = &#39;\\MyFileServer\SharedFolder\init.bak&#39; 
GO&lt;/pre&gt;
&lt;br /&gt;
&lt;strong&gt;Step 3&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;
Creiamo la sottoscrizione dal server publisher&amp;nbsp;utilizzando la &lt;a href=&quot;http://technet.microsoft.com/en-us/library/ms181702.aspx&quot; target=&quot;_blank&quot;&gt;sp_addsubscription&lt;/a&gt;&amp;nbsp;e la&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://technet.microsoft.com/en-us/library/ms175006.aspx&quot; target=&quot;_blank&quot;&gt;sp_addpushsubscription_agent&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
La sp_addsubscription deve essere eseguita specificando:&lt;br /&gt;
@subscription_type = &#39;Push&#39;&lt;br /&gt;
@sync_type = &#39;initialize with backup&#39;&lt;br /&gt;
@backupdevicetype = &#39;disk&#39;&lt;br /&gt;
@backupdevicename = MyPath&lt;br /&gt;
Dove MyPath è il path al backup differenziale appena creato che verrà utilizzato per allineare i dati.&lt;br /&gt;
&lt;br /&gt;
La sp_addpushsubscription_agent deve essere eseguita specificando:&lt;br /&gt;
@job_login = MyLogin&lt;br /&gt;
@job_password = MyPassword&lt;br /&gt;
Dove MyLogin e MyPassword sono Username e Pwd che l&#39;agent utilizzerà per le repliche.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;--Da eseguire sul publisher
use DBPublisher
GO

exec sp_addsubscription 
  @publication = N&#39;TestPub&#39;
  , @subscriber = N&#39;WIN12NODE2&#39;
  , @destination_db = N&#39;DBSubScriber&#39;
  , @subscription_type = N&#39;Push&#39;
  , @sync_type = N&#39;initialize with backup&#39;
  , @backupdevicetype = N&#39;disk&#39;
  , @backupdevicename = N&#39;\\MyFileServer\SharedFolder\init.bak&#39;
  , @article = N&#39;all&#39;
  , @update_mode = N&#39;read only&#39;
  , @subscriber_type = 0

exec sp_addpushsubscription_agent @publication = N&#39;TestPub&#39;
  , @subscriber = N&#39;WIN12NODE2&#39;
  , @subscriber_db = N&#39;DBSubScriber&#39;
  , @job_login = MyLogin
  , @job_password = MyPassword
  , @subscriber_security_mode = 1
  , @frequency_type = 64
  , @frequency_interval = 0
  , @frequency_relative_interval = 0
  , @frequency_recurrence_factor = 0
  , @frequency_subday = 0
  , @frequency_subday_interval = 0
  , @active_start_time_of_day = 0
  , @active_end_time_of_day = 235959
  , @active_start_date = 20130919
  , @active_end_date = 99991231
  , @enabled_for_syncmgr = N&#39;False&#39;
  , @dts_package_location = N&#39;Distributor&#39;
GO

&lt;/pre&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNkk8CpEFsI-GvJt6XPhtom-No-66LtNrOtxKSZujJ1d2Ep_mc7AGk03ww_8SsHPr8IJGhlrEFt38TGpJmYJf76mmVIioPLXIG-EpQTV_G9k_lqJmviX_9IHVQSA8oEQWI_V1vSoiljtHD/s1600/3.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNkk8CpEFsI-GvJt6XPhtom-No-66LtNrOtxKSZujJ1d2Ep_mc7AGk03ww_8SsHPr8IJGhlrEFt38TGpJmYJf76mmVIioPLXIG-EpQTV_G9k_lqJmviX_9IHVQSA8oEQWI_V1vSoiljtHD/s1600/3.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&amp;nbsp;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Se abbiamo fatto tutto correttamente la replica è già operativa e tutte le transazioni applicate al DBPublisher saranno replicate anche sul DBSubscriber.&lt;br /&gt;
Per essere certi che tutto funzioni correttamente&amp;nbsp;possiamo utilizzare il tool di &lt;a href=&quot;http://technet.microsoft.com/en-us/library/ms152751.aspx&quot; target=&quot;_blank&quot;&gt;monitoring della replica&lt;/a&gt;&amp;nbsp;per risolvere eventuali problemi. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW2z_B5YVMjCRpfwPGCtITJQrjwFYg7oWpoJxrm2almyjlsentXXkKqkDxcjAF7EGd08qbMPAMtkg7oP2xLESClaiaclxsFDjsaCdl4aktZpd6X-YsJHuX5De3WrXuesd7_bA5znjkOLsH/s1600/4.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW2z_B5YVMjCRpfwPGCtITJQrjwFYg7oWpoJxrm2almyjlsentXXkKqkDxcjAF7EGd08qbMPAMtkg7oP2xLESClaiaclxsFDjsaCdl4aktZpd6X-YsJHuX5De3WrXuesd7_bA5znjkOLsH/s400/4.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/5405291359259556305/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/09/backuprestore-come-initial-snapshot-di.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/5405291359259556305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/5405291359259556305'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/09/backuprestore-come-initial-snapshot-di.html' title='Backup/Restore come Initial Snapshot di una replica transazionale'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRfcFSSU_rSkWxp7uD2iBOBEB5PYu98dNTbVHPUYw9ZiJIDRpbVDE523qWtedfqrtThy0U2FEUjpc6pBMv7ukvihqcH6gJZ5HbWWqFNI2vBITBNJ1Ys94OquW2gSxOtFRtd3LzFBphefe-/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-1072513338191775326</id><published>2013-09-22T09:30:00.000+02:00</published><updated>2013-09-23T10:06:13.192+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Execution Plan"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance tuning"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2008"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2008 R2"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2012"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type='text'>T-SQL e caricamento dati differenziale..... E le performance ?</title><content type='html'>Immaginiamo questo scenario :&lt;br /&gt;
DBTarget è un DB OLAP che contiene una tabella TargetTable ed è utilizzato per effettuare Business Intelligence&lt;br /&gt;
DBSource è il DB OLTP che contiene una tabella SourceTable ed è utilizzato dai programmi aziendali di gestione.&lt;br /&gt;
Abbiamo la necessità di allineare il contenuto di TargetTable con quello di SourceTable utilizzando T-SQL.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Ho a disposizione 3 strade&lt;br /&gt;
&lt;br /&gt;
Soluzione 1&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Truncate/Delete di TargetTable &lt;/li&gt;
&lt;li&gt;Ri-popolamento totale&amp;nbsp;partendo dai dati di&amp;nbsp;SourceTable &lt;/li&gt;
&lt;/ol&gt;Soluzione 2&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Cerco le righe presenti in TargetTable ma non in SourceTable e se necessario le elimino&lt;/li&gt;
&lt;li&gt;Cerco le righe differenti tra TargetTable e SourceTable e le aggiorno con i dati di SourceTable&lt;/li&gt;
&lt;li&gt;Cerco le righe presenti in SourceTable ma non in TargetTable&amp;nbsp;e le inserisco&lt;/li&gt;
&lt;/ol&gt;Soluzione&amp;nbsp;3 &lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Eseguo il Merge delle tabelle&lt;/li&gt;
&lt;/ol&gt;Il costrutto &lt;a href=&quot;http://technet.microsoft.com/it-it/library/bb510625.aspx&quot; target=&quot;_blank&quot;&gt;Merge,&lt;/a&gt; introdotto dall&#39;edizione SQL Server 2008 (ben 5 anni fa ma che purtroppo non vedo molto utilizzato) consente, con un unico comando, di effettuare Delete, Update ed&amp;nbsp;Insert in una tabella con un solo comando.&lt;br /&gt;
&lt;br /&gt;
Vediamo&amp;nbsp;un paio di&amp;nbsp;esempi.&lt;br /&gt;
&lt;br /&gt;
Creo DBSource con la Sp di popolamento iniziale e quella di simulazione modifica dati&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Create Database DBSource
Go

Use DBSource
Go


Create table SourceTable
(
 id int primary key clustered
 ,campo1 varchar(25)
 ,campo2 varchar(25)
 ,campo3 varchar(25)
)
GO


--Popolo la tabella con circa 16 Milioni di righe
Create Procedure CreateSourceData
as

Truncate table SourceTable

--Popolamento iniziale
;With Cte as (Select 1 Riga Union All Select 1)
 ,Cte4 as (Select A.Riga From Cte A, Cte B)
 ,Cte16 as (Select A.Riga From Cte4 A, Cte4 B)
 ,Cte256 as (Select A.Riga From Cte16 A, Cte16 B)
 ,Cte65536 as (Select A.Riga From Cte256 A, Cte256 B)
 ,CteManyRows as (Select A.Riga From Cte65536 A, Cte256 B)
 ,Results as (Select ROW_NUMBER() Over(Order By Riga)Riga From CteManyRows)
Insert into SourceTable (id, campo1, campo2, campo3)
Select 
 Riga
 ,&#39;Campo1 &#39; + Cast(Riga as Varchar(19)) 
 ,&#39;Campo2 &#39; + Cast(Riga as Varchar(19)) 
 ,&#39;Campo3 &#39; + Cast(Riga as Varchar(19)) 
from Results
Go

--Cancello, Modifico, inserisco il numero di righe
--specificato nel parametro @RowNum
--Le righe coinvolte sono reperite casualmnte grazie all&#39;Order by NewId()
Create Procedure ModifySourceData
@RowNum int
as
--Cancellazione Random
Delete A From SourceTable A
 Inner Join
  (Select Top(@RowNum) id from SourceTable
   Order By NEWID()) B
 On A.id = B.id

--Modifica Random
Update A Set Campo2 = A.campo3
 From SourceTable A
  Inner Join
   (Select Top(@RowNum) id from SourceTable
    Order By NEWID()) B
  On A.id = B.id

--Inserimento di nuove righe
;With Cte as (Select 1 Riga Union All Select 1)
 ,Cte4 as (Select A.Riga From Cte A, Cte B)
 ,Cte16 as (Select A.Riga From Cte4 A, Cte4 B)
 ,Cte256 as (Select A.Riga From Cte16 A, Cte16 B)
 ,Cte65536 as (Select A.Riga From Cte256 A, Cte256 B)
 ,CteManyRows as (Select A.Riga From Cte65536 A, Cte256 B)
 ,Results as (Select ROW_NUMBER() Over(Order By Riga)Riga From CteManyRows)
Insert into SourceTable (id, campo1, campo2, campo3)
Select 
 Riga + 1000000000
 ,&#39;Campo1 &#39; + Cast(Riga + 1000000000 as Varchar(19)) 
 ,&#39;Campo2 &#39; + Cast(Riga + 1000000000 as Varchar(19)) 
 ,&#39;Campo3 &#39; + Cast(Riga + 1000000000 as Varchar(19)) 
from Results
 Where Riga &amp;lt;= @RowNum
Go

&lt;/pre&gt;Creo ora DBTarget con le SP di popolamento iniziale e di allineamento &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Create Database DBTarget
Go

Use DBTarget
Go

Create table TargetTable
(
 id int primary key clustered
 ,campo1 varchar(25)
 ,campo2 varchar(25)
)
GO

--popola la tabella TargetTable con circa 16 milioni
Create Procedure dbo.ResetTable
as
Truncate table TargetTable

;With Cte as (Select 1 Riga Union All Select 1)
 ,Cte4 as (Select A.Riga From Cte A, Cte B)
 ,Cte16 as (Select A.Riga From Cte4 A, Cte4 B)
 ,Cte256 as (Select A.Riga From Cte16 A, Cte16 B)
 ,Cte65536 as (Select A.Riga From Cte256 A, Cte256 B)
 ,CteManyRows as (Select A.Riga From Cte65536 A, Cte256 B)
 ,Results as (Select ROW_NUMBER() Over(Order By Riga)Riga From CteManyRows)
Insert into TargetTable (id, campo1, campo2)
Select 
 Riga
 ,&#39;Campo1 &#39; + Cast(Riga as Varchar(19)) 
 ,&#39;Campo2 &#39; + Cast(Riga as Varchar(19)) 
from Results
Go

--Allinea la tabella TargetTable facendone la truncate e ripopolandola totalmente da SourceTable
Create Procedure dbo.Ripopola
as
Truncate table TargetTable

Insert into TargetTable
Select id, Campo1, Campo2 From [DBSource].[dbo].[SourceTable]
Go


--Allinea la tabella TargetTable effettuando
--1 Delete righe non più presenti in Source
--2 Update Righe modificate in Source
--3 Insert nuove righe da Source
Create Procedure dbo.AllineaSenzaMerge
as

Delete T from TargetTable T
 Where T.id not in (Select id from [DBSource].[dbo].[SourceTable])

--Cerco presenti ma differenti
Update T Set 
 T.campo1 = S.campo1 
 ,T.campo2 = S.campo2
from TargetTable T
 Inner join [DBSource].[dbo].[SourceTable] S
  On T.id = S.id
Where T.campo1 &amp;lt;&amp;gt; S.campo1
 Or T.campo2 &amp;lt;&amp;gt; S.campo2

--Cerco nuovi
Insert Into TargetTable
Select S.id
  ,S.campo1
  ,S.campo2 
from [DBSource].[dbo].[SourceTable] S
 Where S.id not in (Select id from TargetTable)
GO

--Allinea la tabella TargetTable con il solo 
-- omando MERGE
Create Procedure dbo.AllineaConMerge
as

Merge Into TargetTable Target
Using 
(Select id,Campo1,campo2 from [DBSource].[dbo].[SourceTable]) Source
 On Target.id = Source.id
When not matched by Source then
 Delete
When Matched and (target.campo1 != source.campo1 Or target.campo2 != source.campo2) Then
 Update Set target.campo1 = source.campo1
    ,target.campo2 = source.campo2
When not Matched by target then
 Insert (id,campo1,campo2) values(source.id, source.campo1, source.campo2);

GO

&lt;/pre&gt;Ho creato nel DB&amp;nbsp;4 SP&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;dbo.ResetTable= Ripristina la situazione iniziale del test&lt;/li&gt;
&lt;li&gt;dbo.Ripopola = Allina la tabella con un re-inserimento totale dei dati&lt;/li&gt;
&lt;li&gt;dbo.AllineaSenzaMerge = Allinea la tabella eliminando, modificando, inserendo solo le righe necessarie in 3 step T-SQL differenti (Delete, Update, Insert)&lt;/li&gt;
&lt;li&gt;dbo.AllineaConMerge = Allinea la tabella eliminando, modificando, inserendo solo le righe necessarie con il solo comando merge.&lt;/li&gt;
&lt;/ol&gt;Popoliamo la tabella SourceTable di DBSource con circa 16 milioni di Righe. &lt;br /&gt;
N.B. Il caricamento potrebbe essere lento.... &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use DBSource
Go
Exec CreateSourceData 
Go
&lt;/pre&gt;&lt;br /&gt;
&lt;strong&gt;Esempio 1 : Popolamento TargetTable da zero&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Proviamo ad allineare Target&amp;nbsp;con la SP dbo.Ripopola &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use DBTarget
Go
Set statistics Io On
Set Statistics Time On
Go

Exec dbo.Ripopola
Go

Set statistics time off
Set statistics io Off
GO

&lt;/pre&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6g9b0eBEUprHUsIXLNXraAHr9DkPB1Wcesg3JjKLHvqNHSohTodQQ7v-UXjvZ30M1veAjFR8TS5BSA7ZGiXc546wb3oImkQltytUoEP0IvJYjRFLRmR4dnaGn4AQD24i9rWSMImej7Ya0/s1600/1.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6g9b0eBEUprHUsIXLNXraAHr9DkPB1Wcesg3JjKLHvqNHSohTodQQ7v-UXjvZ30M1veAjFR8TS5BSA7ZGiXc546wb3oImkQltytUoEP0IvJYjRFLRmR4dnaGn4AQD24i9rWSMImej7Ya0/s400/1.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
La Sp impiega circa 30 secondi per inserire circa 16 milioni di record (Il disco della macchina è un SSD  ;-) )&lt;br /&gt;
&lt;br /&gt;
Proviamo ad allinearla con la SP dbo.AllineaSenzaMerge&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use DBTarget
Go
Truncate table TargetTable
Go
Set statistics Io On
Set statistics Time On
GO
Exec dbo.AllineaSenzaMerge
GO
Set statistics time off
Set statistics io Off
GO

&lt;/pre&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZmlQZuHheEfgsQk5AvXF9jUrjfeTlOUY7TlyoSGSJnji8aUaGWWJCDaQ-L1HlYP8zWKxQFyIGZNOglnRfJBXohohuWRoPX3gnH1FA3QB8ZV1TuOm4_kYfAoAh8i9zKplgKeVWxZIs6ck-/s1600/2.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZmlQZuHheEfgsQk5AvXF9jUrjfeTlOUY7TlyoSGSJnji8aUaGWWJCDaQ-L1HlYP8zWKxQFyIGZNOglnRfJBXohohuWRoPX3gnH1FA3QB8ZV1TuOm4_kYfAoAh8i9zKplgKeVWxZIs6ck-/s400/2.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Il tempo impiegato è di circa 35 secondi...&lt;br /&gt;
&lt;br /&gt;
Proviamo ora&amp;nbsp;con il comando Merge&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use DBTarget
Go
Truncate table TargetTable
Go
Set statistics Io On
Set statistics Time On
GO
Exec dbo.AllineaConMerge
GO
Set statistics time off
Set statistics io Off
GO

&lt;/pre&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8jHq9kdH6RYObUven1FXHIP7jEP51tL3WkRX7s6gswn4wURnj8B00aquT3_pxeiMV_Qb_pVEQXloPCB9FzXARxVqUzq4bUOteuMUPFfw6wREbTH08gpIqkpRodrCGwCN3c3khqFjs31AF/s1600/3.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8jHq9kdH6RYObUven1FXHIP7jEP51tL3WkRX7s6gswn4wURnj8B00aquT3_pxeiMV_Qb_pVEQXloPCB9FzXARxVqUzq4bUOteuMUPFfw6wREbTH08gpIqkpRodrCGwCN3c3khqFjs31AF/s400/3.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Il Merge impiega circa 44 Secondi.......&lt;br /&gt;
&lt;br /&gt;
In una situazione come questa è ovviamente meglio effettuare il popolamento utilizzando un Insert into dalla tabella sorgente.&lt;br /&gt;
Gli step di Delete e di Update sono inutili quindi è ovvio che le Sp AllineaSenzaMerge e AllineaConMerge siano meno&amp;nbsp;performanti nonostante il numero di operazioni I/O sia lo stesso per tutte 3 le Sp......&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Esempio&amp;nbsp;2 : Allineamento TargetTable con SourceTable (&amp;nbsp;3000000 righe modificate)&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;
Ora che&amp;nbsp;le tabelle Source e Target sono allineate, simuliamo un utilizzo della tabella Source con operazioni di Delete, Update e Insert.&lt;br /&gt;
Simulo la cancellazione, la modifica e l&#39;inserimento di 1000000 di record nella tabella SourceTable.&lt;br /&gt;
In tutto sono 3000000 le righe &quot;modificate&quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use DBSource
Go
Exec ModifySourceData 1000000
Go
&lt;/pre&gt;&lt;br /&gt;
Allineamento con Truncate e Re-inserimento massivo &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use DBTarget
Go
Set statistics Io On
Set Statistics Time On
Go
Exec Ripopola
Go
Set statistics time off
Set statistics io Off
GO
&lt;/pre&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheB50MQ08ymRwS9pnxfUrUuS1VWq7LibwxP1-F7YV0Pvml8NWaeftBV6rxf-47xR-FE8KfFuHk6l0NNWJVaXS80LFTcJy5wBnIhgzrKN7lUMcvoQC4BuhOZXWjZAdq7f4tSldWbYHxBAz_/s1600/4.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheB50MQ08ymRwS9pnxfUrUuS1VWq7LibwxP1-F7YV0Pvml8NWaeftBV6rxf-47xR-FE8KfFuHk6l0NNWJVaXS80LFTcJy5wBnIhgzrKN7lUMcvoQC4BuhOZXWjZAdq7f4tSldWbYHxBAz_/s400/4.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Dato che il numero di righe in SourceTable non è cambiato il tempo d&#39;esecuzione della Sp è praticamente il medesimo del test precedente, circa 30 secondi.&lt;br /&gt;
&lt;br /&gt;
Proviamo con la SP dbo.AllineaSenzaMerge &lt;br /&gt;
N.B. La tabella viene riportata alla condizione precedente con la sp dbo.ResetTable&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use DBTarget
Go
Exec dbo.ResetTable
Go
Set statistics Io On
Set statistics Time On
GO
Exec dbo.AllineaSenzaMerge
GO
Set statistics time off
Set statistics io Off
GO

&lt;/pre&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZopM7luIyYAZ54-8S3XFbArMg1_6VrJBoay4ZeW3zBtHTK-XgV5sl5K79vCx1ZE1tB1OFJIcVT4KSjRt4MKm1pwdvk_vQr_SYTi0YKspRjqNDKcc0Dy3bYJGJCDXicMCiiyh659cK9emA/s1600/8.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZopM7luIyYAZ54-8S3XFbArMg1_6VrJBoay4ZeW3zBtHTK-XgV5sl5K79vCx1ZE1tB1OFJIcVT4KSjRt4MKm1pwdvk_vQr_SYTi0YKspRjqNDKcc0Dy3bYJGJCDXicMCiiyh659cK9emA/s400/8.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Stavolta ha impiegato circa 32 secondi... &lt;br /&gt;
&lt;br /&gt;
Proviamo&amp;nbsp;il Merge&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use DBTarget
Go
Exec dbo.ResetTable
Go
Set statistics Io On
Set statistics Time On
GO
Exec dbo.AllineaConMerge
GO
Set statistics time off
Set statistics io Off
GO

&lt;/pre&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKniKxzbq9iPlEKMFRJW0Yl5GFoLsicuePC6jDNUDVYW5ILtwIwebRkCV4s_4q0GgBmsByJGQeXQec8hnAOViIQr2tH3wL0e06L606hwYkd4sUrN2GpJlO0GI0Y4dGq2FnlLCpKyr0oVua/s1600/9.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKniKxzbq9iPlEKMFRJW0Yl5GFoLsicuePC6jDNUDVYW5ILtwIwebRkCV4s_4q0GgBmsByJGQeXQec8hnAOViIQr2tH3wL0e06L606hwYkd4sUrN2GpJlO0GI0Y4dGq2FnlLCpKyr0oVua/s400/9.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Il Merge ha girato in 24 secondi.....&lt;br /&gt;
&lt;br /&gt;
La spiegazione sta nel numero di operazioni di I/O effettuate. &lt;br /&gt;
La sp dbo.Ripopola deve ricostruire da zero la tabella, quindi implementa moltissimo I/O.&lt;br /&gt;
La sp dbo.AllineaSenzaMerge per ognuno dei 3&amp;nbsp;step deve cercare le righe coinvolte e modificarle, quindi moltissimo I/O....&lt;br /&gt;
Il Merge implementa un solo passaggio e quindi una sola lettura delle tabelle, mentre Update, Delete ed Insert vengono implementati all&#39;unisono....&lt;br /&gt;
Dopotutto meno I/O faccio più veloce vado ed il Merge in questo caso ci aiuta... &lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/1072513338191775326/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/09/t-sql-e-caricamento-dati-differenziale.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/1072513338191775326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/1072513338191775326'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/09/t-sql-e-caricamento-dati-differenziale.html' title='T-SQL e caricamento dati differenziale..... E le performance ?'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6g9b0eBEUprHUsIXLNXraAHr9DkPB1Wcesg3JjKLHvqNHSohTodQQ7v-UXjvZ30M1veAjFR8TS5BSA7ZGiXc546wb3oImkQltytUoEP0IvJYjRFLRmR4dnaGn4AQD24i9rWSMImej7Ya0/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-1775382031382081514</id><published>2013-09-14T10:49:00.000+02:00</published><updated>2013-11-21T13:08:40.235+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Database Maintenance"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance tuning"/><category scheme="http://www.blogger.com/atom/ns#" term="Rebuild Indexes"/><category scheme="http://www.blogger.com/atom/ns#" term="Reorganize Indexes"/><title type='text'>Script Rebuild o Reoganize ?</title><content type='html'>E&#39; sempre necessario fare la rebuild di un indice&amp;nbsp;o posso farne la reorganize ?&lt;br /&gt;
Per dirla in modo estrememente sintetico e semplificato, la Rebuild è molto efficiente &amp;nbsp;ma pesante , la Reorganize meno efficace ma più leggera...&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;La prima è&amp;nbsp;utile quando è necessario ricostruire la struttura al fine di ripristinare il livello di performance adeguato, la seconda è utile quando la struttura non è molto frammentata e le performance sono ancora accettabili.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://technet.microsoft.com/en-us/library/ms189858.aspx&quot; target=&quot;_blank&quot;&gt;Qui&lt;/a&gt; trovate un articolo dettagliato su come determinare la frammentazione di un indice e come intervenire.&lt;br /&gt;
&lt;br /&gt;
Lo script, trasformabile in stored procedure fa riferimento a :&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;@Pages_Limits = numero minimo di datapages che compone l&#39;indice. se l&#39;indice è composto da un numero di data pages inferiore non viene preso in considerazione.&lt;/li&gt;
&lt;li&gt;@Fragmentation_Limits = % di frammentazione sotto la quale viene eseguita la Reorganize. Se la percentuale di frammentazione dell&#39;indice è superiore al valore della variabile viene eseguita la Rebuild.&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;DECLARE @Pages_Limits INT = 1500
DECLARE @Fragmentation_Limits TINYINT = 30
DECLARE @StrCmd VARCHAR(max) = &#39;&#39;

SELECT @StrCmd = @StrCmd +
 &#39;ALTER INDEX &#39; + QUOTENAME(I.name) + &#39; ON &#39; + QUOTENAME(S.name) + &#39;.&#39; + QUOTENAME(O.name) 
 + IIF(F.avg_fragmentation_in_percent &amp;gt; 10 AND F.avg_fragmentation_in_percent &amp;lt; @Fragmentation_Limits,&#39; REORGANIZE&#39;,&#39; REBUILD&#39;)
 + IIF(ISNULL(P.[Partitions],0) &amp;gt; 1,&#39; PARTITION = &#39; + CAST(F.partition_number AS VARCHAR(5)),&#39;&#39;)+ Char(13)
FROM sys.dm_db_index_physical_stats(DB_ID() , NULL, NULL , NULL , &#39;LIMITED&#39;) F
 LEFT JOIN 
        (
     SELECT Object_id
     ,index_id
     ,Count(*) [Partitions]  
     FROM sys.partitions
      GROUP BY Object_id,index_id
        ) P ON F.object_id = P.object_id and F.index_id = P.index_id
 INNER JOIN sys.indexes I
  ON F.object_id = I.object_id and F.index_id = I.index_id
 INNER JOIN sys.all_objects O
  ON F.object_id = O.object_id
 INNER JOIN sys.schemas S
  ON O.schema_id = S.schema_id
WHERE I.type != 0 and F.page_count &amp;gt;= @Pages_Limits
ORDER BY page_count DESC

PRINT(@StrCmd)
&lt;/pre&gt;
&lt;br /&gt;
Lo script genera il comando di ALTER INDEX per tutte le strutture coinvolte&lt;br /&gt;
(Nell&#39;esempio è modificato&amp;nbsp;per monitorare una tabella specifica chiamata SlowQueries&quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL4VBlklXduIdSFmzjFTTrnK4VWtqKOoe7RS4U9qXjJRFEwKt8sqrhEAsVHxP3EkKR33NPGV0qlAPPRyPp9_wpii9f2uJlouvPEFJXU-POzjJ3zjqdOPJOu7gOFyhZL49f87W5vZDDUBL_/s1600/1.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL4VBlklXduIdSFmzjFTTrnK4VWtqKOoe7RS4U9qXjJRFEwKt8sqrhEAsVHxP3EkKR33NPGV0qlAPPRyPp9_wpii9f2uJlouvPEFJXU-POzjJ3zjqdOPJOu7gOFyhZL49f87W5vZDDUBL_/s400/1.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Se si desidera eseguirlo senza preview basta aggiungere il comando di EXEC(@StrCmd)&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;N.B.1.&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;Eseguire Rebuild in ambiente di produzione può impedire l&#39;uso della tabella/indice&amp;nbsp;su cui si sta eseguendo l&#39;operazione con ripercussioni su tutte le connessioni e le attività che tentano di accedervi !!!!!! Da fare con molta cautela !!!&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;N.B.2. Lo script è per SQL Server 2012.&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;Per renderlo compatibile con SQL Server 2005,2008,2008R2 è necessario convertire l&#39;operatore ternario IIF in CASE WHEN.&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/1775382031382081514/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/10/script-rebuild-o-reoganize.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/1775382031382081514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/1775382031382081514'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/10/script-rebuild-o-reoganize.html' title='Script Rebuild o Reoganize ?'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL4VBlklXduIdSFmzjFTTrnK4VWtqKOoe7RS4U9qXjJRFEwKt8sqrhEAsVHxP3EkKR33NPGV0qlAPPRyPp9_wpii9f2uJlouvPEFJXU-POzjJ3zjqdOPJOu7gOFyhZL49f87W5vZDDUBL_/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-8483235761698028895</id><published>2013-09-08T14:45:00.001+02:00</published><updated>2013-09-08T14:45:36.269+02:00</updated><title type='text'>SQL Saturday : Milano 08-10-2013</title><content type='html'>L&#39;8 ottobre 2013 presso l&#39;Innovation Campus di Microsoft in Via Lombardia, 2, Milano si terrà il&amp;nbsp;SQL Saturday con sessioni molto interessanti e speaker italiani ed&amp;nbsp;internazionali.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.sqlsaturday.com/260/schedule.aspx&quot;&gt;Qui&lt;/a&gt;&amp;nbsp;trovate l&#39;agenda.&lt;br /&gt;
&lt;a href=&quot;http://www.sqlsaturday.com/260/eventhome.aspx&quot;&gt;Qui&lt;/a&gt; potete registrarvi.&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/8483235761698028895/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/09/sql-saturday-milano-08-10-2013.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8483235761698028895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8483235761698028895'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/09/sql-saturday-milano-08-10-2013.html' title='SQL Saturday : Milano 08-10-2013'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-3215206770433340570</id><published>2013-09-08T14:29:00.001+02:00</published><updated>2013-10-03T20:29:58.619+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Hekaton"/><category scheme="http://www.blogger.com/atom/ns#" term="In Memory Oltp"/><category scheme="http://www.blogger.com/atom/ns#" term="In-Memory Optimized Tables"/><category scheme="http://www.blogger.com/atom/ns#" term="Isolation level"/><category scheme="http://www.blogger.com/atom/ns#" term="Latch Free"/><category scheme="http://www.blogger.com/atom/ns#" term="Latch Lock Free"/><category scheme="http://www.blogger.com/atom/ns#" term="Lock"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 CTP1"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 novità"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 What&#39;s new"/><category scheme="http://www.blogger.com/atom/ns#" term="Transactions"/><title type='text'>SQL Server 2014 CTP1 : In-Memory Optimized Tables, No Lock and Latch !!!</title><content type='html'>Fino all&#39;edizione 2012 il meccanismo di controllo delle transazioni faceva largo uso di Lock e di Latch, con tutti i problemi derivanti alla loro gestione &lt;br /&gt;
(Consumo di risorse, low performance, etc.... )&lt;br /&gt;
Le In-Memory Optimized Tables introdotte da SQL Server 2014 CTP1 utilizzano un meccanismo di gestione accessi concorrenziali di tipo Optimistic Multiversion, &lt;br /&gt;
che consente alle transazioni di essere Lock e Latch Free.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Ciò non significa assolutamente che le transazioni implementate sulle in-Memory Optimized Tables non siano&lt;br /&gt;
&lt;b&gt;A&lt;/b&gt;tomic&lt;br /&gt;
&lt;b&gt;C&lt;/b&gt;onsistency&lt;br /&gt;
&lt;b&gt;I&lt;/b&gt;solation&lt;br /&gt;
&lt;b&gt;D&lt;/b&gt;urability&lt;br /&gt;
&lt;br /&gt;
Vediamo un esempio di funzionamento.&lt;br /&gt;
&lt;br /&gt;
Creo un Database di test&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Master
Go

CREATE DATABASE Hekaton_Test     
ON PRIMARY(NAME = [PRIMARY],     
   FILENAME = &#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\Hekaton_DiskBasedTable.mdf&#39;)
   ,FILEGROUP [SampleDB_mod_fg] 
    CONTAINS MEMORY_OPTIMIZED_DATA    
     (NAME = [HKDB_mod_dir],FILENAME = &#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\In_Memory_Table&#39;)
LOG ON (name = [SampleDB_log], Filename=&#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\Hekaton_Test_log.ldf&#39;)  
Go

Use Hekaton_Test
Go

Create table MemoryTable
(
 id int not null PRIMARY KEY NONCLUSTERED HASH WITH(BUCKET_COUNT = 1024)
 ,Campo char(30) not null
)WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA); 
GO

;With Cte as(Select 1 Riga union All Select 1)
 ,Cte4 as (Select A.Riga From Cte A, Cte B)
 ,Cte16 as (Select A.Riga From Cte4 A, Cte4 B)
 ,Cte256 as (Select A.Riga From Cte16 A, Cte16 B)
 ,Cte65536 as (Select A.Riga From Cte256 A, Cte256 B)
 ,Results as (Select ROW_NUMBER()Over(Order by Riga) Riga From Cte65536)
Insert into MemoryTable(id, Campo)
Select Riga
       ,Riga
from Results where Riga &amp;lt;= 1024

&lt;/pre&gt;
Simulo l&#39;accesso di due&amp;nbsp;connessioni alla medesima tabella, la prima eseguirà una transazione in&amp;nbsp;update di tutte le righe, la seconda&amp;nbsp;contemporaneamente tenterà la lettura dell&#39;intera tabella.   &lt;br /&gt;
&lt;br /&gt;
Questa la transazione&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;USE Hekaton_Test

BEGIN TRANSACTION

UPDATE MemoryTable WITH(SNAPSHOT) SET campo = &#39;T1 &#39; + campo 

SELECT * FROM MemoryTable WITH(SNAPSHOT)
&lt;/pre&gt;
&lt;div class=&quot;brush:sql&quot;&gt;
&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj87Llch642uLsxmElPeq5LdTPm9E2hXD7ucK7-ftrfbadF0T79VxuM4APBYyMrl_8prwIq0ws52R4iyc6unzcTA8JNAHAgoAAirJuuM-JoBaTY_eUN-k8DIhUO5UFBDqqoiXen-8j1SIQh/s1600/1.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj87Llch642uLsxmElPeq5LdTPm9E2hXD7ucK7-ftrfbadF0T79VxuM4APBYyMrl_8prwIq0ws52R4iyc6unzcTA8JNAHAgoAAirJuuM-JoBaTY_eUN-k8DIhUO5UFBDqqoiXen-8j1SIQh/s400/1.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;clear: both;&quot;&gt;
&lt;/div&gt;
L&#39;aggiornamento è andato a buon fine &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_X-WnmHFAeI_9_d4vEeet25hjoeofWmAzrvnpfV-Hy2RiAlxV2Ylkj_u9wauecgpigXGDinZF9TJvyILpU_wMsCQovMh7bCLBd73vpDMYwk5Fzsbx-7CMb0YD5ylioc_qCnzwnsvcNcIV/s1600/2.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_X-WnmHFAeI_9_d4vEeet25hjoeofWmAzrvnpfV-Hy2RiAlxV2Ylkj_u9wauecgpigXGDinZF9TJvyILpU_wMsCQovMh7bCLBd73vpDMYwk5Fzsbx-7CMb0YD5ylioc_qCnzwnsvcNcIV/s400/2.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;clear: both;&quot;&gt;
&lt;/div&gt;
e la select all&#39;interno della prima connessione ha ovviamente restituito i valori modificati.  &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;N.B.&lt;/b&gt; Senza WITH(SNAPSHOT) l&#39;update e la select della prima connessione restituirebbero un errore.  &lt;br /&gt;
Nella &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dn133169(v=sql.120).aspx&quot;&gt;MSDN&lt;/a&gt; trovate tutte le info sull&#39;utilizzo degli Isolation Level con le In-Memory Optimized Tables. &lt;br /&gt;
&lt;br /&gt;
La&amp;nbsp;prima transazione&amp;nbsp;è&amp;nbsp;attualmente attiva dato che il COMMIT ancora non è stato implementato. &lt;br /&gt;
Cosa succede se la seconda connessione tenta la lettura della tabella ? &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;SELECT * FROM MemoryTable
&lt;/pre&gt;
&lt;br /&gt;
Dato che le In-Memory Optimized tables utilizzano un sistema Optimistic Multiversion non ho lock e&amp;nbsp;di conseguenza no wait, quindi i dati vengono restituiti senza attesa nella loro versione pre-modifica. &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhevddkS-BKU4gqenF07Xm3qj1g_cmpCHWzKb4D7BnwDfU9H13WK_hSMnhA4RL6YqD8cnS_8ahX519Fdxe5HvNMnAKtw8P3VV4V9XOcZxK4o21_BhqkuNUfq94FIhjYXjXBbc6PUtioyG6/s1600/3.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhevddkS-BKU4gqenF07Xm3qj1g_cmpCHWzKb4D7BnwDfU9H13WK_hSMnhA4RL6YqD8cnS_8ahX519Fdxe5HvNMnAKtw8P3VV4V9XOcZxK4o21_BhqkuNUfq94FIhjYXjXBbc6PUtioyG6/s400/3.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;clear: both;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;N.B.&lt;/b&gt; Il multiversioning per le In-Memory Optimized Tables non utilizza il TempDb ma la RAM.&lt;br /&gt;
&lt;br /&gt;
Ovviamente chiudendo con il COMMIT&amp;nbsp;la transazione che ha implementato l&#39;update&amp;nbsp;tutte le successive letture&amp;nbsp;restituiranno i dati modificati.&lt;br /&gt;
&lt;br /&gt;
Ma cosa&amp;nbsp;accade quando 2 transazioni tentano di modificare i medesimi dati contemporaneamente ?&lt;br /&gt;
&lt;br /&gt;
Non avendo ancora effettuato il commit posso eseguire subito una&amp;nbsp;nuova transazione che implementerà una modifica.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;USE Hekaton_Test

BEGIN TRANSACTION

UPDATE MemoryTable WITH(SNAPSHOT) SET campo = &#39;T2 &#39; + campo 

SELECT * FROM MemoryTable WITH(SNAPSHOT)
&lt;/pre&gt;
&lt;br /&gt;
ed ecco il risultato&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaIGzdt7KwQUl4lgKaqmWCbFVQc5JpJck0y7X6-ZlUevEki5Kpt-V6kYc-HDhDwUHJv7ZbWvlyRRae2hH0zS6Je1TElPvgNcvJ_UyPkSMxB57f-EHix59nMv_tFQhSd4DOeIaN0bE8Qyx6/s1600/4.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaIGzdt7KwQUl4lgKaqmWCbFVQc5JpJck0y7X6-ZlUevEki5Kpt-V6kYc-HDhDwUHJv7ZbWvlyRRae2hH0zS6Je1TElPvgNcvJ_UyPkSMxB57f-EHix59nMv_tFQhSd4DOeIaN0bE8Qyx6/s400/4.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;clear: both;&quot;&gt;
&amp;nbsp;&lt;/div&gt;
In questo caso si verifica un conflitto e&amp;nbsp;la transazione&amp;nbsp;viene conclusa con errore.&lt;br /&gt;
In casi come questo è necessario ritentare la transazione. &lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dn169141(v=sql.120).aspx&quot;&gt;Qui&lt;/a&gt; trovate le linee guida per il retry delle transazioni.&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dn133187(v=sql.120).aspx&quot;&gt;Qui&lt;/a&gt; trovate le linee guida sulla selezione dell&#39;isolation level.&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/3215206770433340570/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/09/sql-server-2014-ctp1-in-memory-tables.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/3215206770433340570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/3215206770433340570'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/09/sql-server-2014-ctp1-in-memory-tables.html' title='SQL Server 2014 CTP1 : In-Memory Optimized Tables, No Lock and Latch !!!'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj87Llch642uLsxmElPeq5LdTPm9E2hXD7ucK7-ftrfbadF0T79VxuM4APBYyMrl_8prwIq0ws52R4iyc6unzcTA8JNAHAgoAAirJuuM-JoBaTY_eUN-k8DIhUO5UFBDqqoiXen-8j1SIQh/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-4672931759204622772</id><published>2013-08-21T02:46:00.001+02:00</published><updated>2013-10-25T12:05:09.428+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Execution Plan"/><category scheme="http://www.blogger.com/atom/ns#" term="Hekaton"/><category scheme="http://www.blogger.com/atom/ns#" term="In Memory Oltp"/><category scheme="http://www.blogger.com/atom/ns#" term="In-Memory Optimized Tables"/><category scheme="http://www.blogger.com/atom/ns#" term="Natively compiled stored procedures"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 CTP1"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 novità"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 What&#39;s new"/><title type='text'>SQL Server 2014 CTP1 : Natively compiled stored procedures</title><content type='html'>Un&#39;altra novità introdotta da SQL Server 2014 CTP1 sono le Natively compiled stored procedures. &lt;br /&gt;
Queste SP altro non sono che codice T-SQL compilato nativamente che può essere eseguito dalla CPU senza alcun passaggio intermedio, risparmiando tempo e risorse.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Dato che non sono necessari passaggi intermedi per eseguire una Natively Compiled Stored Procedure è evidente che i miglioramenti in termini di performance possono essere moltissimi.&lt;br /&gt;
&lt;br /&gt;
Facciamo un esempio&lt;br /&gt;
&lt;br /&gt;
Creo un database contenente una In-Memory Table &lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Master
Go

--Creo il DB
CREATE DATABASE Hekaton_Test     
ON PRIMARY(NAME = [PRIMARY],     
   FILENAME = &#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\Hekaton_DiskBasedTable.mdf&#39;)
   ,FILEGROUP [Hekaton_InMemory_FG] 
    CONTAINS MEMORY_OPTIMIZED_DATA    
     (NAME = [Hekaton_InMemory_Dir],FILENAME = &#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\In_Memory_Table&#39;)
LOG ON (name = [Hekaton_log], Filename=&#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\Hekaton_Test_log.ldf&#39;)  
Go

USE Hekaton_Test
Go

--Creo la tabella
CREATE TABLE dbo.MemoryTable
(
 id int not null PRIMARY KEY NONCLUSTERED HASH WITH(BUCKET_COUNT = 65536)
 ,campo varchar(25) COLLATE Latin1_General_100_BIN2 not null
)WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA); 
GO

--La popolo
With Cte as (Select 1 Riga union All Select 1)
 ,Cte4 as (Select A.Riga from Cte A, cte B)
 ,Cte16 as (Select A.Riga from Cte4 A, Cte4 B)
 ,Cte256 as (Select A.Riga from Cte16 A, Cte16 B)
 ,Cte65536 as (Select A.Riga from Cte256 A, Cte256 B)
 ,results as (Select Row_number() over(Order by Riga) Riga from Cte65536)
insert into MemoryTable 
Select Riga, &#39;Valore &#39; + Cast(Riga as varchar(5)) From results
GO

&lt;/pre&gt;&lt;br /&gt;
Creo ora una Stored Procedure tradizionale e la Natively Stored Procedure&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;--Creo una Stored Procedure tradizionale
CREATE PROCEDURE Dbo.SP_TSQL_MEMORY_TAB
 @id int
AS
 declare @c varchar(25)

 Select @c = A.campo from dbo.Memorytable A Where A.id = @id

 Update dbo.Memorytable Set campo = campo + &#39;AAAA&#39; Where id = @id
 
 Delete from dbo.Memorytable where id = @id
 Insert into dbo.Memorytable values(@id, @c)
GO

--Creo una Natively Compiled Stored Procedure
CREATE PROCEDURE Dbo.SP_NATIVE_COMPILATION_MEMORY_TAB
 @id int not null
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS BEGIN ATOMIC WITH
(
 TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = &#39;us_english&#39;
)
 declare @c varchar(25)

 Select @c = A.campo from dbo.Memorytable A Where A.id = @id

 Update dbo.Memorytable Set campo = campo + &#39;AAAA&#39; Where id = @id
 
 Delete from dbo.Memorytable where id = @id
 Insert into dbo.Memorytable values(@id, @c)

END
GO
&lt;/pre&gt;&lt;br /&gt;
Escludendo alcune Keyword particolari la sintassi non è molto dissimile da quella necessaria alla creazione di SP tradizionali.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;WITH NATIVE_COMPILATION&lt;/b&gt; : Identifica che stiamo creando una SP Natively compiled&lt;br /&gt;
&lt;b&gt;SCHEMABINDING&lt;/b&gt; : E&#39; obbligatorio che la SP sia creata con lo SCHEMABINDING&lt;br /&gt;
&lt;b&gt;EXECUTE AS&lt;/b&gt; : E&#39; obbligatorio e supporta i valori OWNER, SELF o &lt;i&gt;user&lt;/i&gt;. CALLER non è supportato.&lt;br /&gt;
&lt;b&gt;BEGIN ATOMIC&lt;/b&gt; : Identifica il corpo della SP che sarà eseguito come un unico blocco atomico. &lt;br /&gt;
&lt;br /&gt;
Il blocco Atomic dovrà inoltre avere specificato anche&lt;br /&gt;
&lt;b&gt;TRANSACTION ISOLATION LEVEL &lt;/b&gt; :E&#39; obbligatorio e specifica il &lt;a href=&quot;http://technet.microsoft.com/en-us/library/dn133175(v=sql.120).aspx&quot;&gt;Transaction Isolation Level&lt;/a&gt; utilizzato dal body della Sp&lt;br /&gt;
&lt;b&gt;LANGUAGE &lt;/b&gt; : E&#39; obbligatorio e specifica il Language che sarà utilizzato dalla sp.&lt;br /&gt;
&lt;br /&gt;
Eseguo ora la stored procedure tradizionale per ogni riga contenuta nella in-memory table e mi faccio restituire il tempo di esecuzione in millisecondi.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;DECLARE @t datetime;
SET @t = GETDATE();

declare @i int = 1
While @i &amp;lt;= 65536
begin

 
 --Exec sp_executesql N&#39;Dbo.SP_NATIVE_COMPILATION_MEMORY_TAB @i&#39;,N&#39;@i int&#39;,@i=@i
 Exec sp_executesql N&#39;Dbo.SP_TSQL_MEMORY_TAB @i&#39;,N&#39;@i int&#39;,@i=@i
 Set @i+=1

end
select DATEDIFF( MILLISECOND , @t , current_timestamp );
&lt;/pre&gt;Ed ecco il risultato  &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwTjj2nFFd2ksG7Q4bZAfIbOF91Hb1clC5alWlj1xN-riw3wPuuPfuABAfDOddxiP__REelbl_PmKmOdPt7Lrh8O8YRWB5S63HUC1l5yKigpUuWE1TPUogDJSaHVpzVQDwmRaX-rqFmDuX/s1600/1.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwTjj2nFFd2ksG7Q4bZAfIbOF91Hb1clC5alWlj1xN-riw3wPuuPfuABAfDOddxiP__REelbl_PmKmOdPt7Lrh8O8YRWB5S63HUC1l5yKigpUuWE1TPUogDJSaHVpzVQDwmRaX-rqFmDuX/s400/1.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;Ora eseguo la Natively Compiled Stored Procedure e mi faccio restituire il tempo di esecuzione in millisecondi &lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;DECLARE @t datetime;
SET @t = GETDATE();

declare @i int = 1
While @i &amp;lt;= 65536
begin

 
 Exec sp_executesql N&#39;Dbo.SP_NATIVE_COMPILATION_MEMORY_TAB @i&#39;,N&#39;@i int&#39;,@i=@i
 --Exec sp_executesql N&#39;Dbo.SP_TSQL_MEMORY_TAB @i&#39;,N&#39;@i int&#39;,@i=@i
 Set @i+=1

end
select DATEDIFF( MILLISECOND , @t , current_timestamp );
&lt;/pre&gt;&lt;br /&gt;
Ed ecco il risultato  &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKvpflsINsZk5nl5r8Dc5omrdGddG2yQtsAPrTMKgRghkrfOQsj9MATRQBOBWUZudswyg461_XjHhQxahrjjl-2ieZ5ZlFbnnO28qo-375OsmBDnB-uQJJnfqOB69ATkh7IxtwnkoWj36h/s1600/2.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKvpflsINsZk5nl5r8Dc5omrdGddG2yQtsAPrTMKgRghkrfOQsj9MATRQBOBWUZudswyg461_XjHhQxahrjjl-2ieZ5ZlFbnnO28qo-375OsmBDnB-uQJJnfqOB69ATkh7IxtwnkoWj36h/s400/2.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;Passare da circa 50 secondi a meno di 20 solo compilando nativamente la stored procedure è un ottimo guadagno. &lt;br /&gt;
Peccato non sia così facile trasformare le Stored procedure tradizionali in Natively Compiled. &lt;br /&gt;
In primo luogo queste nuove SP possono accedere solo a In-Memory Table(non supportano l&#39;accesso a Disk-Based Table) e non tutti i comandi T-SQL sono supportati. &lt;br /&gt;
Per esempio non è possibile farne l&#39;alter. &lt;br /&gt;
&lt;a href=&quot;http://technet.microsoft.com/en-us/library/dn246937(v=sql.120).aspx&quot;&gt;Qui&lt;/a&gt; trovate la lista dei cosa è supportato e cosa non lo è.&lt;br /&gt;
&lt;br /&gt;
Ma effettivamente, dove viene salvato il codice ?  &lt;br /&gt;
Se guardiamo l&#39;INFORMATION_SCHEMA.ROUTINES vediamo che entrambe le SP sono salvate come metadati nelle tabelle di sistema. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Select SPECIFIC_CATALOG
  ,SPECIFIC_SCHEMA 
  ,SPECIFIC_NAME
  ,ROUTINE_TYPE
  ,ROUTINE_DEFINITION  
from Information_Schema.ROUTINES
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUnVF_-GuieFrj7wfMnY1snPP4lj23aSNcxqgCBWiOyAjFL_zRoUy8II89IBPCr6RUFSJ6dirtb0mvFNJaxW149KDYqgzkkon6UhedPY4KODMk0aZ7wnxWp869PUeSNVNz-czkl2Wr0J8f/s1600/3.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUnVF_-GuieFrj7wfMnY1snPP4lj23aSNcxqgCBWiOyAjFL_zRoUy8II89IBPCr6RUFSJ6dirtb0mvFNJaxW149KDYqgzkkon6UhedPY4KODMk0aZ7wnxWp869PUeSNVNz-czkl2Wr0J8f/s400/3.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Se però la Natively Compiled sp fosse disponibile solo nei metadati i vantaggi in performance che abbiamo appena visto non li avremmo ottenuti. &lt;br /&gt;
SQL Server, all&#39;atto della creazione della Sp, oltre ad inserirla nei metadati, crea un modulo compilato nativamente e lo carica in memoria rendendolo istantaneamente disponbile, non solo, salva anche un file .c sul disco.&lt;br /&gt;
Questo file contiene la definizione del modulo nativo che sql ha generato e che ha caricato in memoria. &lt;br /&gt;
&lt;br /&gt;
E&#39; possibile reperire la lista di tutti i moduli creati dagli utenti e i loro file .c con una nuova DMV, la sys.dm_os_loaded_modules. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;SELECT * FROM sys.dm_os_loaded_modules
WHERE DESCRIPTION = &#39;XTP Native DLL&#39;
&lt;/pre&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOhD8363CcB88HALEwd0aNr0NNyfhohPs9slOM3x2RLR9w-O8j8Jm4uITM9h3DZLcSLyYIyk8ZNGrySRX2iMoDWp6V3pLqv3_42RPlCoozoHwAyNtmYSUMQ1IMug2OCZkypyGAG8ZJWGOv/s1600/4.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOhD8363CcB88HALEwd0aNr0NNyfhohPs9slOM3x2RLR9w-O8j8Jm4uITM9h3DZLcSLyYIyk8ZNGrySRX2iMoDWp6V3pLqv3_42RPlCoozoHwAyNtmYSUMQ1IMug2OCZkypyGAG8ZJWGOv/s400/4.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
E questo è un estratto del contenuto del file .c&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:c#&quot;&gt;struct hkt_485576768
{
 long hkc_1;
 unsigned short hkvdo[2];
};
struct hkis_48557676800002
{
 long hkc_1;
};
struct hkif_48557676800002
{
 long hkc_1;
};
unsigned short GetSerializeSize_485576768(
 struct HkRow const* hkRow)
{
 struct hkt_485576768 const* row = ((struct hkt_485576768 const*)hkRow);
 return ((row-&amp;gt;hkvdo)[1]);
}
HRESULT Serialize_485576768(
 struct HkRow const* hkRow,
 unsigned char* buffer,
 unsigned short bufferSize,
 unsigned short* copySize)
{
 return (RowSerialize(hkRow, (GetSerializeSize_485576768(hkRow)), buffer, bufferSize, copySize));
}
HRESULT Deserialize_485576768(
 struct HkTransaction* tx,
 struct HkTable* table,
 unsigned char const* data,
 unsigned short datasize,
 struct HkRow** hkrow)
{
 return (RowDeserialize(tx, table, data, datasize, sizeof(struct hkt_485576768), (sizeof(struct hkt_485576768) + 25), hkrow));
}
unsigned short GetSerializeRecKeySize_485576768(
 struct HkRow const* hkRow)
{
 struct hkt_485576768 const* row = ((struct hkt_485576768 const*)hkRow);
 unsigned short size = sizeof(struct hkif_48557676800002);
 return size;
}
&lt;/pre&gt;&lt;br /&gt;
Questo file serve solo per troubleshooting dato che il modulo è già in memoria.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Attenzione&lt;/b&gt; : Dato che queste SP non verranno più Ricompilate se non a seguito di Restart del server, è indispensabile crearle quando la/le tabelle che andranno ad utilizzare conterranno un campione rappresentativo dei dati e le statistiche dovranno essere aggiornate. &lt;br /&gt;
&lt;a href=&quot;http://technet.microsoft.com/en-us/library/dn249342(v=sql.120).aspx&quot;&gt;Qui&lt;/a&gt; trovate maggiori dettagli.&lt;br /&gt;
&lt;br /&gt;
I File risultanti dalla compilazione di queste SP non sono compresi nel backup del database perché non sono necessari. &lt;br /&gt;
Al momento del restore le Natively compiled Stored Procedure saranno ricompilate, dopotutto nei metadati è presente la loro definizione.&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/4672931759204622772/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/08/sql-server-2014-ctp1-natively-compiled.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/4672931759204622772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/4672931759204622772'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/08/sql-server-2014-ctp1-natively-compiled.html' title='SQL Server 2014 CTP1 : Natively compiled stored procedures'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwTjj2nFFd2ksG7Q4bZAfIbOF91Hb1clC5alWlj1xN-riw3wPuuPfuABAfDOddxiP__REelbl_PmKmOdPt7Lrh8O8YRWB5S63HUC1l5yKigpUuWE1TPUogDJSaHVpzVQDwmRaX-rqFmDuX/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-5530656437589814094</id><published>2013-07-21T23:10:00.002+02:00</published><updated>2013-07-21T23:28:09.233+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Buffer Pool"/><category scheme="http://www.blogger.com/atom/ns#" term="Dirty Pages"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance tuning"/><category scheme="http://www.blogger.com/atom/ns#" term="Ram"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 CTP1"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 novità"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 What&#39;s new"/><title type='text'>SQL Server 2014 CTP1 : Buffer Pool Extension</title><content type='html'>Le attività di read &amp; write da e per i dischi sono le più pesanti che un RDBMS deve sostenere. &lt;br /&gt;
La &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dn133176(v=sql.120).aspx&quot;&gt;Buffer Pool Extension&lt;/a&gt; di SQL 2014 alleggerisce il carico di I/O mantenendo elevato il throughput dei dischi.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
SQL Server carica in un&#39;area di memoria RAM detta Buffer Pool tutte le datapages richieste dalle nostre operazioni. &lt;br /&gt;
Quelle che hanno subito modifiche (dirty pages) verranno riportate sul disco con una operazione asincrona. &lt;br /&gt;
Maggiore è il tempo in cui le pagine risiedono nel buffer pool (page lifetime expetancy) migliori saranno le performance. &lt;br /&gt;
Se l&#39;istanza di sql però soffre di memory pressure (Page lifetime molto basso) allora sarà costretta a continue operazioni di lettura dal/scrittura sul disco&lt;br /&gt;
delle data pages , siano esse Dirty pages o Clean pages(Pagine che NON hanno subito modifiche). &lt;br /&gt;
&lt;br /&gt;
Per risolvere il problema si potevano seguire 2 strade :&lt;br /&gt;
1) Aggiungere RAM&lt;br /&gt;
2) Aggiungere dischi ad alta velocità&lt;br /&gt;
&lt;br /&gt;
Ora possiamo anche scegliere la via della Buffer Pool Extension.&lt;br /&gt;
In pratica diciamo al buffer pool standard di utilizzare oltre alla Ram anche un file su disco SSD per contenere le datapages richieste dalle operazioni degli utenti.&lt;br /&gt;
&lt;br /&gt;
Con questo comando possiamo abilitarla:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;USE MASTER
GO

ALTER SERVER CONFIGURATION 
SET BUFFER POOL EXTENSION ON
    (FILENAME = &#39;E:\Extension.BPE&#39;, SIZE = 32 GB);&lt;/pre&gt;&lt;br /&gt;
Il disco E:\ è un SSD, Extension.BPE è il file contenente l&#39;estensione del buffer pool ed è allocato in modo statico a 32 GB. &lt;br /&gt;
La dimensione del file dipende dalla dimensione Max della ram associata a SQL Server.&lt;br /&gt;
Microsoft consiglia di rispettare un rapporto di 1:16 tra  Max Memory e l&#39;estensione del buffer pool. &lt;br /&gt;
&lt;br /&gt;
D&#39;ora in poi SQL Server utilizzerà questo file in ausilio al buffer pool in RAM. &lt;br /&gt;
Per onor di cronaca solo le clean pages, cioè pagine che non hanno subito modifiche, vengono scritte nella buffer pool extension. &lt;br /&gt;
Le dirty pages risiedono solo nel buffer pool in ram, questo rende le operazioni di &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms189573(v=sql.120).aspx&quot;&gt;checkpoint&lt;/a&gt; più rapide. &lt;br /&gt;
Lo spostamento tra il buffer pool e la sua estensione delle clean page viene eseguito dal Buffer Manager.&lt;br /&gt;
Questa gestione ibrida del buffer pool consente di migliorare parecchio le operazioni di lettura in ambienti a rischio di memory pressure.&lt;br /&gt;
&lt;br /&gt;
Non si dovrebbe modificare la configurazione del buffer pool extension una volta attivato, soprattutto in produzione.&lt;br /&gt;
Disabilitarlo o rimuoverlo potrebbe penalizzare in modo drastico le performance. &lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/5530656437589814094/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/07/sql-server-2014-ctp1-buffer-pool.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/5530656437589814094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/5530656437589814094'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/07/sql-server-2014-ctp1-buffer-pool.html' title='SQL Server 2014 CTP1 : Buffer Pool Extension'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-7861195058968884347</id><published>2013-06-30T10:30:00.000+02:00</published><updated>2013-06-30T10:30:01.919+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Rebuild Indexes"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 CTP1"/><title type='text'>SQL Server 2014 CTP1 : Rebuild Index Online</title><content type='html'>Una delle novità introdotta da SQL Server 2014 Ctp1 è quella di poter specificare il comportamento che deve intraprendere la rebuild con opzione online qualora una risorsa della tabella stessa fosse in uso da un&#39;altra transazione.&lt;br /&gt;
&lt;br /&gt;
Ricostruire gli indici è un&#39;operazione che andrebbe effettuata in modo frequente soprattutto nei database OLTP che subiscono moltissime scritture ed allo stesso tempo moltissime letture al fine di mantenere elevato il grado delle performance nelle fasi di ricerca. &lt;br /&gt;
Grazie all&#39;opzione ONLINE = ON possiamo ricostruire gli indici e anche durante questa fase assicurare alle altre connessioni una normale operatività.&lt;br /&gt;
Se però una transazione dovesse rimanere in esecuzione per lungo tempo la rebuild non proseguirebbe la sua attività fino a che le risorse in uso dalla transazione non torneranno disponibili. &lt;br /&gt;
&lt;br /&gt;
Fino alla versione 2012 era possibile eseguire il rebuild online di una tabella senza specificare per quanto tempo l&#39;operazione avesse dovuto attendere per accedere ad una risorsa in uso da un&#39;altra connessione. In pratica non era possibile decidere se dare &quot;precedenza&quot; all&#39;operazione di rebuild o alla query.&lt;br /&gt;
Inoltre la rebuild di una singola partizione di una tabella non era supportata.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Con l&#39;attuale versione durante un&#39;operazione di rebuild on line, qualora una transazione blocchi delle risorse nella tabella, la rebuild stessa viene sospesa in attesa che la transazione bloccante rilasci le risorse. Se la transazione, per un qualche errore dovesse rimanere appesa per un lungo periodo, la rebuild non si potrebbe completare in tempo utile.&lt;br /&gt;
&lt;br /&gt;
Vediamo cosa accade &lt;br /&gt;
&lt;br /&gt;
Su un&#39;istanza SQL Server 2012 Sp1 Enterprise creo un database contenente una tabella partizionata [TestTable] e la popolo con 4 milioni di righe.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;USE MASTER
GO

CREATE DATABASE TestRebuild2012 
Go 
ALTER DATABASE TestRebuild2012 
ADD FILEGROUP [PartizioneUno] 
GO 

ALTER DATABASE TestRebuild2012 
ADD FILEGROUP [PartizioneDue] 
GO 

ALTER DATABASE TestRebuild2012 
ADD FILEGROUP [PartizioneTre] 
GO 

ALTER DATABASE TestRebuild2012 
ADD FILEGROUP [PartizioneQuattro] 
GO   
ALTER DATABASE TestRebuild2012 
ADD FILE ( NAME = N&#39;p1&#39;, FILENAME = N&#39;E:\SQL2012_MSSQLSERVER\User Database\p1.ndf&#39;) 
TO FILEGROUP [PartizioneUno] 
GO 

ALTER DATABASE TestRebuild2012 
ADD FILE ( NAME = N&#39;p2&#39;, FILENAME = N&#39;E:\SQL2012_MSSQLSERVER\User Database\p2.ndf&#39;) 
TO FILEGROUP [PartizioneDue] 
GO 

ALTER DATABASE TestRebuild2012 
ADD FILE ( NAME = N&#39;p3&#39;, FILENAME = N&#39;E:\SQL2012_MSSQLSERVER\User Database\p3.ndf&#39;) 
TO FILEGROUP [PartizioneTre] 
GO 

ALTER DATABASE TestRebuild2012 
ADD FILE ( NAME = N&#39;p4&#39;, FILENAME = N&#39;E:\SQL2012_MSSQLSERVER\User Database\p4.ndf&#39;) 
TO FILEGROUP [PartizioneQuattro] 
GO   

USE TestRebuild2012 
Go 


CREATE PARTITION FUNCTION testPF (int)
AS RANGE LEFT FOR VALUES (1000000, 2000000, 3000000);
Go

CREATE PARTITION SCHEME testScheme
AS PARTITION testPF
TO ( [PartizioneUno],[PartizioneDue],[PartizioneTre],[PartizioneQuattro] );
Go

CREATE TABLE TestTable
(
 id INT
 ,campo VARCHAR(25)
 ,valore VARCHAR(25)
)
ON testScheme(id)

CREATE CLUSTERED INDEX idxClustered on TestTable(id) 


;WITH Cte as (SELECT 1 Riga UNION ALL SELECT 1)
 ,Cte4 as (SELECT A.Riga FROM Cte A, Cte B)
 ,Cte16 as (SELECT A.Riga FROM Cte4 A, Cte4 B)
 ,Cte256 as (SELECT A.Riga FROM Cte16 A, Cte16 B)
 ,Cte65536 as (SELECT A.Riga FROM Cte256 A, Cte256 B)
 ,CteBig as (SELECT A.Riga FROM Cte65536 A, Cte65536 B)
 ,Results as (SELECT ROW_NUMBER()OVER(ORDER BY Riga) Riga FROM CteBig)
INSERT INTO TestTable
SELECT TOP 4000000 
 Riga
 ,&#39;Campo &#39; + Cast(Riga AS VARCHAR(10)) 
 ,&#39;valore &#39; + Cast(Riga AS VARCHAR(10)) 
FROM Results
&lt;/pre&gt;&lt;br /&gt;
Apro una connessione ed eseguo la rebuild online dell&#39;indice clustered, cioè della tabella.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;ALTER INDEX idxClustered ON TestTable
REBUILD 
WITH (ONLINE = ON)
&lt;/pre&gt;&lt;br /&gt;
Da un&#39;altra connessione eseguo la modifica di una sola riga ma non ne faccio il commit (In questo modo mantengo per lungo tempo i Lock sulla risorsa)&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;BEGIN TRANSACTION
UPDATE TestTable SET Valore = &#39;Mod &#39; + Valore
 WHERE id = 1500000
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
L&#39;activity monitor mostra cosa sta accadendo....&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghJlLNmPLOBYPWDgqxPx6MP0_HR0nBCtMh6mPuBtIcrp45WLUlPanMg7LO-aARttSOPpXNTQajTu7jIRpW0-QcxnHYkW7Cgmrg1o4j5eXmInavID8mr19PWGN3M6MMNuiefWRfIuJxDu_y/s1372/1.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghJlLNmPLOBYPWDgqxPx6MP0_HR0nBCtMh6mPuBtIcrp45WLUlPanMg7LO-aARttSOPpXNTQajTu7jIRpW0-QcxnHYkW7Cgmrg1o4j5eXmInavID8mr19PWGN3M6MMNuiefWRfIuJxDu_y/s1372/1.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Come potete vedere la rebuild è in stato SUSPENDED, sta attendendo di accedere alla risora in uso dall&#39;update.&lt;br /&gt;
Se eseguo il COMMIT o la ROLLBACK dell&#39;operazione di update la rebuild entra in RUNNING e può essere completata.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdzIXWKKXdeOBFZ_lWcm_6ni12tcIlk_MpwJ2k0m4rSgluG6haly7iqOBEAQhlBEOJcYBmo2hNbSat8lWadddG49KTtnq0YFflpQEHX6Mz7YaO0vaohBO07sTgVlz0UDJVvLiVOISIxP4I/s1403/2.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdzIXWKKXdeOBFZ_lWcm_6ni12tcIlk_MpwJ2k0m4rSgluG6haly7iqOBEAQhlBEOJcYBmo2hNbSat8lWadddG49KTtnq0YFflpQEHX6Mz7YaO0vaohBO07sTgVlz0UDJVvLiVOISIxP4I/s1403/2.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
Con SQL Server 2014 CTP1 è stata introdotta la possibilità di specificare come un&#39;operazione di rebuild online di un indice si deve comportare qualora un&#39;altra transazione stia elaborando una o più righe della tabella stessa.&lt;br /&gt;
&lt;br /&gt;
Su un&#39;istanza SQL Server 2014 CTP1 creo un database contenente una tabella partizionata [TestTable] e la popolo con 4 milioni di righe.&lt;br /&gt;
N.B. Il Database ha la stessa identica struttura del suo gemello in versione SQL 2012. Cambia solo il nome ed il path dei file.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;CREATE DATABASE TestRebuild2014 
Go 

ALTER DATABASE TestRebuild2014 
ADD FILEGROUP [PartizioneUno] 
GO 

ALTER DATABASE TestRebuild2014 
ADD FILEGROUP [PartizioneDue] 
GO 

ALTER DATABASE TestRebuild2014 
ADD FILEGROUP [PartizioneTre] 
GO 

ALTER DATABASE TestRebuild2014 
ADD FILEGROUP [PartizioneQuattro] 
GO   

ALTER DATABASE TestRebuild2014 
ADD FILE ( NAME = N&#39;p1&#39;, FILENAME = N&#39;E:\Data\p1.ndf&#39;) 
TO FILEGROUP [PartizioneUno] 
GO 

ALTER DATABASE TestRebuild2014 
ADD FILE ( NAME = N&#39;p2&#39;, FILENAME = N&#39;E:\Data\p2.ndf&#39;) 
TO FILEGROUP [PartizioneDue] 
GO 

ALTER DATABASE TestRebuild2014 
ADD FILE ( NAME = N&#39;p3&#39;, FILENAME = N&#39;E:\Data\p3.ndf&#39;) 
TO FILEGROUP [PartizioneTre] 
GO 

ALTER DATABASE TestRebuild2014 
ADD FILE ( NAME = N&#39;p4&#39;, FILENAME = N&#39;E:\Data\p4.ndf&#39;) 
TO FILEGROUP [PartizioneQuattro] 
GO   

USE TestRebuild2014 
Go 


CREATE PARTITION FUNCTION testPF (int)
AS RANGE LEFT FOR VALUES (1000000, 2000000, 3000000);
Go

CREATE PARTITION SCHEME testScheme
AS PARTITION testPF
TO ( [PartizioneUno],[PartizioneDue],[PartizioneTre],[PartizioneQuattro] );
Go

CREATE TABLE TestTable
(
 id INT
 ,campo VARCHAR(25)
 ,valore VARCHAR(25)
)
ON testScheme(id)

CREATE CLUSTERED INDEX idxClustered on TestTable(id) 


;WITH Cte as (SELECT 1 Riga UNION ALL SELECT 1)
 ,Cte4 as (SELECT A.Riga FROM Cte A, Cte B)
 ,Cte16 as (SELECT A.Riga FROM Cte4 A, Cte4 B)
 ,Cte256 as (SELECT A.Riga FROM Cte16 A, Cte16 B)
 ,Cte65536 as (SELECT A.Riga FROM Cte256 A, Cte256 B)
 ,CteBig as (SELECT A.Riga FROM Cte65536 A, Cte65536 B)
 ,Results as (SELECT ROW_NUMBER()OVER(ORDER BY Riga) Riga FROM CteBig)
INSERT INTO TestTable
SELECT TOP 4000000 
 Riga
 ,&#39;Campo &#39; + Cast(Riga AS VARCHAR(10)) 
 ,&#39;valore &#39; + Cast(Riga AS VARCHAR(10)) 
FROM Results
&lt;/pre&gt;&lt;br /&gt;
Provo ad eseguire il rebuild online dell&#39;intera tabella.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;ALTER INDEX idxClustered ON TestTable
REBUILD 
WITH (
  ONLINE = ON 
  (
   WAIT_AT_LOW_PRIORITY 
    (MAX_DURATION = 1
    , ABORT_AFTER_WAIT = BLOCKERS)
  )
 )
&lt;/pre&gt;&lt;br /&gt;
La sintassi prevede delle nuove opzioni :&lt;br /&gt;
MAX_DURATION : Tempo massimo (in minuti) d&#39;attesa per accedere alla risorsa.&lt;br /&gt;
ABORT_AFTER_WAIT : Al termine del periodo di attesa specificato in MAX_DURATION viene eseguito il Kill dell&#39;operazione bloccante se il parametro è BLOCKERS o della rebuild stessa se il parametro è SELF.&lt;br /&gt;
&lt;br /&gt;
Apro una connessione ed eseguo la modifica di una sola riga ma non ne faccio il commit (In questo modo mantengo per lungo tempo i Lock sulla risorsa)&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;BEGIN TRANSACTION
UPDATE TestTable SET Valore = &#39;Mod &#39; + Valore
WHERE id = 1500000
&lt;/pre&gt;&lt;br /&gt;
Come si comporta quindi l&#39;engine ? &lt;br /&gt;
Inizialmente esattamente come se ci trovassimo in SQL Server 2012, la rebuild viene messa in suspend....&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2R5w_G_IeyS8sI_5niePq1hv1ntfoDMdG5Wi6RY9mrJocU6S9K1Ted9pLTlXRFNiot032KCUzV7kxl7iTL6HYLANj65A7iULZOPmAtvnQWEYkKjpHKXfqlhVgc2xbkqM0H4WKHaNQ8kW8/s949/3.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2R5w_G_IeyS8sI_5niePq1hv1ntfoDMdG5Wi6RY9mrJocU6S9K1Ted9pLTlXRFNiot032KCUzV7kxl7iTL6HYLANj65A7iULZOPmAtvnQWEYkKjpHKXfqlhVgc2xbkqM0H4WKHaNQ8kW8/s949/3.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
ma dato che abbiamo specificato il parametro MAX_DURATION = 1 la rebuild attende per il tempo max specificato, nel nostro esempio un minuto, scaduto il quale implementa il Kill della/delle transazioni bloccanti. In questo modo la rebuild potrà continuare le sue attività.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE7v3MA1ZMDNCTeB3Rsdq2pfeAS41S51almETDS9l4-HH4OR-0dXAuopAUIYyOhY1eCFPgaor-7lIoXOoV0oyaf1Z186-bTDTJLT-eWZwQ9spwIti8SKJHs55b6Rre2EYtxuHhF46mxMtJ/s971/4.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE7v3MA1ZMDNCTeB3Rsdq2pfeAS41S51almETDS9l4-HH4OR-0dXAuopAUIYyOhY1eCFPgaor-7lIoXOoV0oyaf1Z186-bTDTJLT-eWZwQ9spwIti8SKJHs55b6Rre2EYtxuHhF46mxMtJ/s971/4.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Cosa succede alla transazione dell&#39;update se tento di dare il commit ?&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9PBeP9FKniBHTRamMYOH-1761-w6VSX3Tei47G-mDPBFVRJV6wceDA_INHYdbOu-XbHl0cjIyV2gRNcl68EvP9hjhFqBM-B-9rIJ-ch2dWniMneEzk-4Pkp6_2WDQVz4MUiGgnHZsxxrv/s1140/5.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9PBeP9FKniBHTRamMYOH-1761-w6VSX3Tei47G-mDPBFVRJV6wceDA_INHYdbOu-XbHl0cjIyV2gRNcl68EvP9hjhFqBM-B-9rIJ-ch2dWniMneEzk-4Pkp6_2WDQVz4MUiGgnHZsxxrv/s1140/5.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Dato che la rebuild ha fatto il Kill della connessione riceve un&#39;errore. &lt;br /&gt;
(Automaticamente l&#39;engine ha inoltre implementato la rollback dell&#39;update)&lt;br /&gt;
&lt;br /&gt;
Se avessi specificato il parametro ABORT_AFTER_WAIT = SELF il comportamento sarebbe stato l&#39;opposto, la transazione avrebbe avuto priorità e l&#39;engine avrebbe effettuato la kill della rebuild.&lt;br /&gt;
&lt;br /&gt;
Dato che la tabella è stata creata come partizionata potrei voler effettuare il rebuild online di una sola partizione ma......&lt;br /&gt;
L&#39;operazione di rebuild di una sola partizione con Sql Server 2012 non è supportata.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuA2kvKnccd2lFOJlyxnU-k1i4Vyucprn6ffvG3FX5PYU0UmS1Sd_71esL7iCSac-aY766bAqlEwijEq47-DVI-eCefkJEYN4yOR0JxUrxmv8RHlW-3DRFqk83oERiLfidP4XQHq9gHrck/s501/6.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuA2kvKnccd2lFOJlyxnU-k1i4Vyucprn6ffvG3FX5PYU0UmS1Sd_71esL7iCSac-aY766bAqlEwijEq47-DVI-eCefkJEYN4yOR0JxUrxmv8RHlW-3DRFqk83oERiLfidP4XQHq9gHrck/s501/6.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Mentre in Sql Server 2014 CTP1 è possibile fare il rebuild online di una sola partizione&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;ALTER INDEX idxClustered ON TestTable
REBUILD PARTITION = 2
WITH (ONLINE = ON (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1, ABORT_AFTER_WAIT = BLOCKERS)))

&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglZDS2_uG3rqb1PgD8fE6akqGim_frpXo5pN2rLXzcqlSUrh0SdvHuQA04j8VhFJfS4v4cRfFlpMzpvVEj9_T30U5y0ESwoD44dCQRfUQEVdRDbry-nnq5UVSe3EJLpDi1Vhshnz1qqtXl/s667/7.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglZDS2_uG3rqb1PgD8fE6akqGim_frpXo5pN2rLXzcqlSUrh0SdvHuQA04j8VhFJfS4v4cRfFlpMzpvVEj9_T30U5y0ESwoD44dCQRfUQEVdRDbry-nnq5UVSe3EJLpDi1Vhshnz1qqtXl/s667/7.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Se non vengono specificate le opzioni MAX_DURATION e ABORT_AFTER_WAIT il comportamento implementato è quello descritto per SQL Server 2012.&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/7861195058968884347/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/06/sql-server-2014-ctp1-rebuild-index.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/7861195058968884347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/7861195058968884347'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/06/sql-server-2014-ctp1-rebuild-index.html' title='SQL Server 2014 CTP1 : Rebuild Index Online'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghJlLNmPLOBYPWDgqxPx6MP0_HR0nBCtMh6mPuBtIcrp45WLUlPanMg7LO-aARttSOPpXNTQajTu7jIRpW0-QcxnHYkW7Cgmrg1o4j5eXmInavID8mr19PWGN3M6MMNuiefWRfIuJxDu_y/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-2685618527231505039</id><published>2013-06-26T02:47:00.002+02:00</published><updated>2014-01-16T17:05:38.259+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="datapage"/><category scheme="http://www.blogger.com/atom/ns#" term="Hekaton"/><category scheme="http://www.blogger.com/atom/ns#" term="In Memory Oltp"/><category scheme="http://www.blogger.com/atom/ns#" term="In-Memory Optimized Tables"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance"/><category scheme="http://www.blogger.com/atom/ns#" term="Ram"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2014 CTP1"/><title type='text'>Sql Server 2014 CTP1 : Un vero In-Memory Oltp Database management System</title><content type='html'>Oggi è uscito SQL Server 2014 CTP1 !!!&lt;br /&gt;
Era necessario visto che SQL 2012 è poco più di anno che è uscito in RTM ? Cioè... ancora non abbiamo apprezzato tutte le sue potenzialità che Microsoft ha pensato bene di rilasciare, seppur in CTP il suo successore..... &lt;br /&gt;
Che cosa avranno mai sviluppato per giustificare un così repentino rilascio ?!?!?&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Una cosa su tutte.... Hekaton, o nel suo nome definitivo In-Memory OLTP !!!!&lt;br /&gt;
&lt;br /&gt;
In-Memory OLTP è tecnologia tutta nuova che anche grazie alla diffusione dei sistemi HW a 64 bit, consente di sfruttare in modo impressionante la RAM della macchina, migliorando di 10x,o addirittura 100x le performance dei nostri processi sfruttando quelle che sono definite &quot;In-Memory optimized Tables&quot; e le &quot;Natively compiled stored procedures&quot;.&lt;br /&gt;
&lt;br /&gt;
Le In-Memory Optimized Table non sono altro che delle tabelle che risiedono interamente in memoria con i loro indici.&lt;br /&gt;
&lt;br /&gt;
Le Natively compiled stored procedures sono degli oggetti compilati in &quot;Machine Code&quot;  che di conseguenza potrebbero ulteriormente migliorare le perfomance nel process dei dati . Questi oggetti li affronterò in un post successivo.&lt;br /&gt;
&lt;br /&gt;
Ovviamente ciò non significa che questi nuovi oggetti siano la panacea per tutti i mali dei nostri DB....&lt;br /&gt;
In-Memory OLTP è una tecnologia che va sfruttata con raziocinio per poter ottenere il top delle performance senza &quot;sprechi&quot; inutili di RAM.&lt;br /&gt;
&lt;br /&gt;
Ovviamente non sono utilizzabili su piattaforme 32 bit....&lt;br /&gt;
&lt;br /&gt;
Fino a SQL Server&amp;nbsp;2012 l&#39;utilizzo della RAM da parte dell&#39;engine era esclusivamente fatto per la gestione dei dati in fase di processo sotto forma di datapage. Mano a mano che essi &quot;invecchiavano&quot; venivano scaricati senza troppi riguardi dalla RAM.... Se poi una query ne avesse nuovamente fatto esplicita richiesta essi sarebbero stati riletti dal disco, con ovvie ripercussioni sulle performance dovute alle problematiche di accesso allo storage, di sincronizzazione delle transazioni, di allocazione della RAM, di utilizzo della CPU etc... Il tutto si traduce in performance non sempre all&#39;altezza soprattutto in sistemi non particolarmente dotati in quanto a memoria ma che subiscono moltissime transazioni contemporanee.&lt;br /&gt;
&lt;br /&gt;
Con SQL Server 2012 sono stati inoltre introdotti i ColumnStore Index e xVelocity che hanno migliorato le performance in modo incredibile semplicemente sfruttando in modo più intensivo la RAM.&lt;br /&gt;
Column Store Index ed xVelocity hanno mostrato in minima parte quale vantaggio comporta un migliore utilizzo della RAM, seppur con qualche limitazione(Per esempio una tabella dotata di columnstore index non poteva più subire scritture).&lt;br /&gt;
&lt;br /&gt;
Ok bello.... Ma come funzionano le In-Memory Optimized Table ?&lt;br /&gt;
Partiamo dal fatto che NON funzionano come le tabelle tradizionali che possiamo d&#39;ora in poi definire Disk-based tables. A differenza di queste ultime, le In-Memory Tables non hanno la classica allocazione basata su datapages così come gli indici non hanno la classica struttura B-Tree. Sono strutturalmente concepite in modo totalmente differente. Queste tabelle mantengono costantemente la loro struttura ed i dati in RAM. La loro creazione ha una sintassi leggermente differente rispetto a quella delle tabelle tradizionali.&lt;br /&gt;
&lt;br /&gt;
Il vantaggio prestazionale è dato dal fatto che l&#39;engine non ha la necessità di leggere le datapages contenenti i dati dal disco e di posizionarle nella buffer cache perché i dati sono SEMPRE presenti in ram. Ogni operazione su queste tabelle è implementata in RAM. Queste tabelle sono poi corredate di un&#39;insieme di file di Checkpoint che sì risiedono sul disco, ma sono utilizzati solo ed esclusivamente nelle fasi di recovery. Questi file risiedono in un filestream filegroup &lt;br /&gt;
N.B. Non è necessario abilitare la feature del Filestream dal Configuration Manager per poter sfruttare le In-Memory Tables.&lt;br /&gt;
&lt;br /&gt;
Il Database deve essere quindi creato specificando un apposito Filegroup repository dei file di checkpoint.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Master
Go

CREATE DATABASE Hekaton_Test     
ON PRIMARY(NAME = [PRIMARY],     
   FILENAME = &#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\Hekaton_DiskBasedTable.mdf&#39;)
   ,FILEGROUP [Hekaton_InMemory_FG] 
    CONTAINS MEMORY_OPTIMIZED_DATA    
     (NAME = [Hekaton_InMemory_Dir],FILENAME = &#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\In_Memory_Table&#39;)
LOG ON (name = [Hekaton_log], Filename=&#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Hekaton_Test\Hekaton_Test_log.ldf&#39;)  
Go

&lt;/pre&gt;
&lt;br /&gt;
L&#39;opzione CONTAINS MEMORY_OPTIMIZED_DATA identifica il/i filegroup che conterranno i file di checkpoint.&lt;br /&gt;
&lt;br /&gt;
Prima di creare la tabella In-Memory è bene sapere che NON tutti i tipi dato sono supportati.&lt;br /&gt;
I tipi di dati supportati sono :&lt;br /&gt;
bit&lt;br /&gt;
inyint&lt;br /&gt;
smallint&lt;br /&gt;
int&lt;br /&gt;
bigint&lt;br /&gt;
money&lt;br /&gt;
smallmoney&lt;br /&gt;
float&lt;br /&gt;
real&lt;br /&gt;
datetime&lt;br /&gt;
smalldatetime&lt;br /&gt;
datetime2&lt;br /&gt;
date&lt;br /&gt;
time&lt;br /&gt;
char(n)&lt;br /&gt;
varchar(n)&lt;br /&gt;
nchar(n)&lt;br /&gt;
nvarchar(n)&lt;br /&gt;
sysname &lt;br /&gt;
binary(n)&lt;br /&gt;
varbinary(n)&lt;br /&gt;
Uniqueidentifier &lt;br /&gt;
&lt;br /&gt;
Non sono supportati i tipi di dati LOB, Xml, CLR e il (max).&lt;br /&gt;
&lt;br /&gt;
Una riga non deve assolutamente superare la lunghezza di 8060 byte. Non sono previste ROW_OVERFLOW Allocation Unit.&lt;br /&gt;
La tabella deve avere almeno un indice e non può averne più di 8.&lt;br /&gt;
Tutte le tabelle, escludendo quelle create con l&#39;opzione SCHEMA_ONLY devono avere una Primary Key definita.&lt;br /&gt;
Tutti gli indici necessari devono essere creati al momento della create della tabella.&lt;br /&gt;
In questo momento sono supportate le sole Windows Collate BIN2.&lt;br /&gt;
&lt;br /&gt;
Non è possibile definire Foreign Key, Check, DML Trigger, Unique Index oltre alla Pk, identity.... &lt;br /&gt;
Non posso modificarne lo schema e non posso aggiungere indici dopo la creazione della tabella.&lt;br /&gt;
&lt;br /&gt;
Se per ottenere delle performance eccezionali siamo disposti a rinunciare a quanto detto allora possiamo procedere, altrimenti meglio optare per le tabelle tradizionali.&lt;br /&gt;
&lt;br /&gt;
Creo la tabella In-Memory Table&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Hekaton_Test  
Go
Create table MemoryTable
(
 id int not null PRIMARY KEY NONCLUSTERED HASH WITH(BUCKET_COUNT = 5000000)
 ,Nome varchar(25) COLLATE Latin1_General_100_BIN2 not null
 ,Cognome varchar(50) COLLATE Latin1_General_100_BIN2 not null
 ,Indirizzo varchar(50) COLLATE Latin1_General_100_BIN2
 INDEX inMemoryIdx NONCLUSTERED HASH (Cognome,Nome) WITH(BUCKET_COUNT = 5000000) 
)WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY); 
GO
&lt;/pre&gt;
&lt;br /&gt;
Come vedete la sintassi differisce di poco dal comando DDL tradizionale.&lt;br /&gt;
Ho il solito Create table seguito dalla definizione dei campi.&lt;br /&gt;
NONCLUSTERED HASH WITH(BUCKET_COUNT = 1024) identifica il tipo di indice che vado a creare.&lt;br /&gt;
&lt;br /&gt;
La CTP1 supporta solo indici HASH (Nel &lt;a href=&quot;http://sqlblog.com/blogs/kalen_delaney/archive/2013/06/05/hekaton-whitepaper.aspx&quot;&gt;Blog&lt;/a&gt; di Kalen Delaney trovate un&#39;ottima descrizione di come funzionano)&lt;br /&gt;
Detto per sommicapi... Un Hash index altro non è che un array di puntatori che consentono di accedere alle righe della tabella grazie ad una funzione di hash sulla chiave dell&#39;indice stesso, ogni elemento dell&#39;array è chiamato Hash Bucket. E&#39; indispensabile selezionare un BUCKET_COUNT adeguato alla cardinalità attesa dei dati contenuti nella tabella. Come spiegato bene da Kalen Delaney un valore sottostimato causa la crescita della row chain che diminuisce le performance, un valore troppo elevato spreca memoria.&lt;br /&gt;
&lt;br /&gt;
Se non si conosce la cardinalità è bene ripiegare su &lt;a href=&quot;http://tipsandtrickssqlserver.blogspot.fr/2013/11/sql-server-2014-range-index-vs-hash.html&quot; target=&quot;_blank&quot;&gt;Range index&lt;/a&gt; che saranno disponibili dalla CTP2.&lt;br /&gt;
&lt;br /&gt;
L&#39;opzione MEMORY_OPTIMIZED = ON identifica che la tabella è di tipo in-memory&lt;br /&gt;
L&#39;opzione DURABILITY può assumere 2 valori :&lt;br /&gt;
1) SCHEMA_AND_DATA = Significa che la definizione della tabella ed i suoi dati dovranno SEMPRE risiedere in memoria ed in caso di restart del server essi dovranno essere ricostruiti partendo dai file di checkpoint e dal T-Log&lt;br /&gt;
2) SCHEMA_ONLY = Le modifiche ai dati non vengono loggate, ciò significa che a seguito del shutdown dell&#39;istanza i dati eventualmente contenuti saranno irrimediabilmente persi. Il restart dell&#39;istanza comporta la ricreazione della tabella totalmente priva di dati. Questa modalità la trovo utile per aumentare ulteriormente le performance durante le fasi di ETL che necessitano di tabelle di staging.&lt;br /&gt;
&lt;br /&gt;
Per fare un raffronto di performance creo la medesima tabella anche in modo tradizionale&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Hekaton_Test  
Go
Create Table DiskTable
(
 id int Primary Key Clustered
 ,Nome varchar(25)
 ,Cognome varchar(50)
 ,Indirizzo varchar(50)
 INDEX OnDiskIdx NONCLUSTERED (Cognome,Nome)
)
ON [PRIMARY]
GO&lt;/pre&gt;
&lt;br /&gt;
Popolo Entrambe le tabelle con 5000000 di record&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Hekaton_Test  
Go

--Tabella Disk Based

Set statistics Io On
Set statistics Time On
;With Cte as(Select 1 Riga union All Select 1)
 ,Cte4 as (Select A.Riga From Cte A, Cte B)
 ,Cte16 as (Select A.Riga From Cte4 A, Cte4 B)
 ,Cte256 as (Select A.Riga From Cte16 A, Cte16 B)
 ,Cte65536 as (Select A.Riga From Cte256 A, Cte256 B)
 ,CteMany as (Select A.Riga From Cte65536 A, Cte65536 B)
 ,Results as (Select ROW_NUMBER()Over(Order by Riga) Riga From CteMany)
Insert into DiskTable(id, nome, Cognome, indirizzo)
Select Riga
  , &#39;Nome &#39; + Cast(Riga as char(8)) 
  , &#39;Cognome &#39; + Cast(Riga as char(8))     
  , &#39;Indirizzo &#39; + Cast(Riga as char(8)) 
from Results where Riga &amp;lt;= 5000000
Set statistics Io Off
Set statistics Time Off

--Tabella In-Memory

Set statistics Io on
Set statistics Time on

;With Cte as(Select 1 Riga union All Select 1)
 ,Cte4 as (Select A.Riga From Cte A, Cte B)
 ,Cte16 as (Select A.Riga From Cte4 A, Cte4 B)
 ,Cte256 as (Select A.Riga From Cte16 A, Cte16 B)
 ,Cte65536 as (Select A.Riga From Cte256 A, Cte256 B)
 ,CteMany as (Select A.Riga From Cte65536 A, Cte65536 B)
 ,Results as (Select ROW_NUMBER()Over(Order by Riga) Riga From CteMany)
Insert into MemoryTable(id, nome, Cognome, indirizzo)
Select Riga
  , &#39;Nome &#39; + Cast(Riga as char(8)) 
  , &#39;Cognome &#39; + Cast(Riga as char(8))     
  , &#39;Indirizzo &#39; + Cast(Riga as char(8)) 
from Results where Riga &amp;lt;= 5000000
Set statistics Io Off
Set statistics Time Off
GO&lt;/pre&gt;
Ecco qui i risultati
&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;
&lt;/div&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWfR5m7-njhi3nQdRyl6ju6TDxBfFZWLYHH3eo1oV5szg9nsBdN7Mu9QYcSF07Z4FMBmKL-gQ_GY-Srzpfw4ekxZMyF2xiqhHVOr1AbOcma_ScRHqrQYqFsXMWM7nNkJk-GQtXlaIPRVVi/s1600/1Disk.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWfR5m7-njhi3nQdRyl6ju6TDxBfFZWLYHH3eo1oV5szg9nsBdN7Mu9QYcSF07Z4FMBmKL-gQ_GY-Srzpfw4ekxZMyF2xiqhHVOr1AbOcma_ScRHqrQYqFsXMWM7nNkJk-GQtXlaIPRVVi/s400/1Disk.PNG&quot; /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;
&lt;/div&gt;
Come potete vedere per inserire 5000000 Record la tabella tradizionale ha impiegato 2 minuti e mi restituisce il numero di datapages coinvolte dall&#39;operazione. Tengo a precisare che sto utilizzando un disco SSD per la virtual Machine, quindi le performance di I/O sono ottime anche per la disk-based Table

&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaacEarxBdmpwePHz-wy0skg87dZJNH9O1FF11BUcgDbqn44CPyey1YXTv6zjQ3_50nwE4uRmD8hjbrPt1TG2n48Y2ILGQwNf1egR85zgTCkDAla1ZgJHt8mkJ9J1zCZ84X4Kg-6Ybg_XF/s1600/2.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaacEarxBdmpwePHz-wy0skg87dZJNH9O1FF11BUcgDbqn44CPyey1YXTv6zjQ3_50nwE4uRmD8hjbrPt1TG2n48Y2ILGQwNf1egR85zgTCkDAla1ZgJHt8mkJ9J1zCZ84X4Kg-6Ybg_XF/s400/2.PNG&quot; /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
L&#39;inserimento nella tabella In-Memory non restituisce nessun valore relativo all&#39;I/O dato che NON utilizza l&#39;allocazione tradizionale a datapages e come tempo d&#39;esecuzione restituisce 12 secondi......&lt;br /&gt;
&lt;br /&gt;
Non c&#39;è che dire.... Un guadagno notevolissimo in termini di performance !!! Dopotutto la Ram è sempre molto più veloce del disco....&lt;br /&gt;
Anche di un disco SSD ;-)&lt;br /&gt;
&lt;br /&gt;
Direi che la tecnologia In-Memory sia davvero il nuovo punto di svolta per ottenere performance sempre migliori.&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/2685618527231505039/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/06/sql-server-2014-ctp1-un-vero-in-memory.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/2685618527231505039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/2685618527231505039'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/06/sql-server-2014-ctp1-un-vero-in-memory.html' title='Sql Server 2014 CTP1 : Un vero In-Memory Oltp Database management System'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWfR5m7-njhi3nQdRyl6ju6TDxBfFZWLYHH3eo1oV5szg9nsBdN7Mu9QYcSF07Z4FMBmKL-gQ_GY-Srzpfw4ekxZMyF2xiqhHVOr1AbOcma_ScRHqrQYqFsXMWM7nNkJk-GQtXlaIPRVVi/s72-c/1Disk.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-3473792920889573307</id><published>2013-06-25T21:01:00.002+02:00</published><updated>2013-06-25T21:02:20.508+02:00</updated><title type='text'>Windows Server R2 e SQL Server 2014 Ctp1</title><content type='html'>&lt;a href=&quot;http://technet.microsoft.com/en-US/evalcenter/dn205290.aspx&quot;&gt;Qui&lt;/a&gt; potete fare il download della CTP1 di SQL Server 2014&lt;br /&gt;
&lt;a href=&quot;http://www.microsoft.com/en-us/server-cloud/windows-server/windows-server-2012-r2.aspx&quot;&gt;Qui&lt;/a&gt; potete scaricare la preview di Windows Server 2012 R2&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/3473792920889573307/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/06/windows-server-r2-e-sql-server-2014-ctp1.html#comment-form' title='1 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/3473792920889573307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/3473792920889573307'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/06/windows-server-r2-e-sql-server-2014-ctp1.html' title='Windows Server R2 e SQL Server 2014 Ctp1'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-8420598750508942697</id><published>2013-06-19T14:32:00.000+02:00</published><updated>2013-06-19T14:32:07.782+02:00</updated><title type='text'>WPC 2013</title><content type='html'>Sono aperte le iscrizioni alla WPC 2013, la più importante conference italiana per quanto riguarda le tecnologie Microsoft !!!&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.wpc2013.it/&quot;&gt;Qui&lt;/a&gt; trovate tutte le info...&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/8420598750508942697/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/06/wpc-2013.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8420598750508942697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8420598750508942697'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/06/wpc-2013.html' title='WPC 2013'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-8551532917687744369</id><published>2013-06-19T13:50:00.002+02:00</published><updated>2013-06-19T14:02:14.747+02:00</updated><title type='text'>SQL Server 2014 !!!!</title><content type='html'>Non abbiamo ancora sfruttato appieno le potenzialità di SQL Server 2012 che è già in preparazione la release della Ctp di SQL Server 2014.....&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.microsoft.com/en-us/sqlserver/sql-server-2014.aspx&quot;&gt;Qui&lt;/a&gt; il link ufficiale...&lt;br /&gt;
&lt;a href=&quot;http://blogs.msdn.com/b/nullinterface/archive/2013/06/06/sql-server-2014-first-look.aspx&quot;&gt;Qui &lt;/a&gt;trovate ulteriori info sulle novità della nuova edizione.....&lt;br /&gt;
&lt;a href=&quot;http://technet.microsoft.com/it-IT/evalcenter/dn205292.aspx&quot;&gt;Qui&lt;/a&gt; potete iscrivervi per ricevere la notifica della Ctp che dovrebbe uscire a breve....&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/8551532917687744369/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/06/sql-server-2014.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8551532917687744369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8551532917687744369'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/06/sql-server-2014.html' title='SQL Server 2014 !!!!'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-8816562946887277252</id><published>2013-05-26T02:03:00.000+02:00</published><updated>2013-05-26T02:03:32.611+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Execution Plan"/><category scheme="http://www.blogger.com/atom/ns#" term="Modellazione"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2005"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2008"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><category scheme="http://www.blogger.com/atom/ns#" term="Troubleshooting"/><title type='text'>SQL Server 2012 : Viste, problemi e soluzioni....</title><content type='html'>Comodissime le viste, non c&#39;è che dire, salvo il caso in cui vadano in errore, non ci restituiscano tutti i campi che ci aspetteremmo o peggio ancora, ci restituiscano campi con valori incoerenti.&lt;br /&gt;
Se create correttamente sono un ausilio perfetto per reperire i dati in modo semplice e performante.... Sempre che si mettano in opera alcuni semplicissimi accorgimenti.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Creo un db di esempio &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Master
Go

create database TestMetaData
Go 

Use TestMetaData
Go


Create table TestTable1
(
 T1id int
 ,T1campo1 varchar(25)
 ,T1campo2 varchar(25)
 ,T1campo3 varchar(25)
)

Create table TestTable2
(
 T2id int
 ,T2campo1 varchar(25)
 ,T2campo2 varchar(25)
 ,T2campo3 varchar(25)
)


;with cte as (Select 1 Riga union all Select 1)
 ,cte4 as (select A.Riga from cte A, Cte B)
 ,results as (select Row_number() Over(Order by Riga)Riga from cte4)
Insert into TestTable1 
Select 
 Riga
 ,&#39;Campo1 - &#39; + Cast(Riga as varchar(5)) 
 ,&#39;Campo2 - &#39; + Cast(Riga as varchar(5))
 ,&#39;Campo3 - &#39; + Cast(Riga as varchar(5))
from results

;with cte as (Select 1 Riga union all Select 1)
 ,cte4 as (select A.Riga from cte A, Cte B)
 ,results as (select Row_number() Over(Order by Riga)Riga from cte4)
Insert into TestTable2 
Select 
 Riga
 ,&#39;Campo1 - &#39; + Cast(Riga as varchar(5)) 
 ,&#39;Campo2 - &#39; + Cast(Riga as varchar(5))
 ,&#39;Campo3 - &#39; + Cast(Riga as varchar(5))
from results

Create View TestView
as
Select * from dbo.TestTable1
Go
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Caso 1 : La vista va in errore dopo avere modificato una tabella&lt;/b&gt; &lt;br /&gt;
&lt;br /&gt;
Creo ora una vista denominata TestViewDropColumn che restituisce tutte le colonne e tutte le righe della tabella TestTable1 &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Create View TestViewDropColumn
as
Select * from dbo.TestTable1
Go
&lt;/pre&gt;&lt;br /&gt;
Come vedete l&#39;ho creata con una Select *, mi aspetto quindi che tutte le colonne della tabella vengano restituite dalla vista, ed in effetti è così...&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXy4xSqFmm_nLn9jnuM4jknzONOYUzmL_QpX4wnhYTlj3D0nOqvsRBPY5vWGywUkVUF58x7ZmI4g-nK7dHsHBAeyb-5dn6H-xidoEIqCqQQU-qBNF57rbwKe5v0hs1lyJn_bzzAN57Mg0z/s1600/1.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXy4xSqFmm_nLn9jnuM4jknzONOYUzmL_QpX4wnhYTlj3D0nOqvsRBPY5vWGywUkVUF58x7ZmI4g-nK7dHsHBAeyb-5dn6H-xidoEIqCqQQU-qBNF57rbwKe5v0hs1lyJn_bzzAN57Mg0z/s320/1.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Cosa succede se elimino una colonna dalla tabella TestTable1 dopo aver creato la vista e faccio una query sulla vista stessa?&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Alter table dbo.TestTable1 drop column T1campo3
GO
Select * from TestViewDropColumn
&lt;/pre&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqWI2iURILgNAHSnloMGJZDOdE-5ByWMtHdWgKztox4JmRJ_2ZXbfxFmk9mznt0HGIF5I66EHuj08MHiCdGlsy7_wi4W_j-7Ka1ttmpyDOpBAw2dYQRUjVwQkhz3pB9kv6_EAnlcex85XH/s1600/2.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqWI2iURILgNAHSnloMGJZDOdE-5ByWMtHdWgKztox4JmRJ_2ZXbfxFmk9mznt0HGIF5I66EHuj08MHiCdGlsy7_wi4W_j-7Ka1ttmpyDOpBAw2dYQRUjVwQkhz3pB9kv6_EAnlcex85XH/s320/2.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Succede che la vista va in errore.....&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Caso 2 : La vista non restituisce tutte le colonne contenute in una tabella&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Creo una vista sulla tabella dbo.TestTable2&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Create View TestViewAddColumn
as
Select * from dbo.TestTable2
Go
&lt;/pre&gt;&lt;br /&gt;
Anche in questo caso la vista è creata con Select *.&lt;br /&gt;
Aggiungo ora una colonna di tipo int e autoincrementate alla tabella dbo.TestTable2&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Alter table dbo.TestTable1 add NewField int identity
&lt;/pre&gt;&lt;br /&gt;
Vediamo cosa succede se eseguo una select sulla vista e poi sulla tabella&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdt87fxXP26gto7ui9miZFm3fat-zKjYAiA_oV7SaYMTxoAd6_IEOaBi_2_2T1Pbn7xkmfo2RSgIhyuumqwuX2VWIthsAdCXpvXgZ6CbSqjY8qUfmf98YD3WUj6ai1Hf96DLR6M7xMc7bK/s1600/3.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdt87fxXP26gto7ui9miZFm3fat-zKjYAiA_oV7SaYMTxoAd6_IEOaBi_2_2T1Pbn7xkmfo2RSgIhyuumqwuX2VWIthsAdCXpvXgZ6CbSqjY8qUfmf98YD3WUj6ai1Hf96DLR6M7xMc7bK/s320/3.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
In questo caso la vista non restituisce la nuova colonna mentre la seconda select, direttamente sulla tabella, funziona alla perfezione.....&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Caso 3 : La vista restituisce dati incongruenti &lt;/b&gt; &lt;br /&gt;
&lt;br /&gt;
In questo caso creo una vista contenente una join tra dbo.TestTable1 e dbo.TestTable2&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Create View TestViewJoin
as
Select T1.*, T2.* 
 from dbo.TestTable1 T1
 inner join dbo.TestTable2 T2 on T1.T1id = T2.T2id 
Go
&lt;/pre&gt;&lt;br /&gt;
Aggiungo una nuova colonna alla tabella dbo.TestTable1&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Alter table dbo.TestTable1 add ComputedColumn as (T1campo1 + T1Campo2)
&lt;/pre&gt;&lt;br /&gt;
Eseguo la vista &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Select * from TestViewJoin
&lt;/pre&gt;&lt;br /&gt;
ed ecco il risultato &lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA49kqtQwsm3Aux2PQhX7TAKv94e_fMsOE9lLYYgfd9RrbGb_10afIoWUUSUxstfNxcNusJ8sDp_FfxvQE7Y1nDGK-DxqvADpbA0BemBXP1SJZ0W51vzYRvHg381AC4dW4wEwnSbxJRyTs/s1600/4.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA49kqtQwsm3Aux2PQhX7TAKv94e_fMsOE9lLYYgfd9RrbGb_10afIoWUUSUxstfNxcNusJ8sDp_FfxvQE7Y1nDGK-DxqvADpbA0BemBXP1SJZ0W51vzYRvHg381AC4dW4wEwnSbxJRyTs/s320/4.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Come vedete la vista non da errore ma restituisce i valori in modo totalmente errato.&lt;br /&gt;
Questo secondo me è il caso peggiore perché rischia di compromettere in modo devastante e totalmente imprevedibile le applicazioni che fanno riferimento alla vista. &lt;br /&gt;
Il valore &quot;Campo1 - 4Campo2 - 4&quot; è il valore relativo alla colonna &quot;ComputedColumn&quot; aggiunta alla tabella dbo.TestTable1, non è di certo il valore della colonna T2id della tabella dbo.TestTable2. &lt;br /&gt;
&lt;br /&gt;
Come facciamo a porre rimedio ai problemi ?&lt;br /&gt;
&lt;br /&gt;
In modo semplice, richiamando la stored procedure di sistema sp_refreshview che aggiorna i metadati della vista specificata.&lt;br /&gt;
Nel mio caso devo aggiornare tutte 3 le viste create per risolvere i problemi&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Exec sp_refreshview TestViewDropColumn
Exec sp_refreshview TestViewAddColumn
Exec sp_refreshview TestViewJoin
&lt;/pre&gt;&lt;br /&gt;
Se rieseguo le select dalle viste tutto funzionerà in modo corretto&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Select * from TestViewDropColumn
Select * from TestViewAddColumn
Select * from TestViewJoin
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSJSUDZJHseU9EFw9pzaPrlHVw3hlwTOmEX-mBFek77TFRv9ka4OX9uwJM8Jt3qSyjZZAJd3BMSiukD65Nvv3_-AFlTpQOxGo09zya389haPoAMKrgGoGlkPjdo_IyiyZBpqwrXvAk0iyR/s1600/5.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSJSUDZJHseU9EFw9pzaPrlHVw3hlwTOmEX-mBFek77TFRv9ka4OX9uwJM8Jt3qSyjZZAJd3BMSiukD65Nvv3_-AFlTpQOxGo09zya389haPoAMKrgGoGlkPjdo_IyiyZBpqwrXvAk0iyR/s320/5.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Come vedete ora le tre viste restituiscono i risultati aspettati.&lt;br /&gt;
&lt;br /&gt;
Per evitare che i casi d&#39;esempio si verifichino abbiamo 3 strade:&lt;br /&gt;
&lt;br /&gt;
1. Eseguire una &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms173846.aspx&quot;&gt;ALTER VIEW&lt;/a&gt; a seguito di aggiornamenti delle tabelle referenziate&lt;br /&gt;
2. Eseguire un refresh con la &lt;a href=&quot;http://technet.microsoft.com/en-us/library/ms187821.aspx&quot;&gt;sp_refreshview&lt;/a&gt; a seguito di aggiornamenti delle tabelle referenziate&lt;br /&gt;
3. Creare le viste con l&#39;opzione &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms187956.aspx&quot;&gt;SCHEMABINDING&lt;/a&gt; che impedisce qualunque modifica strutturale alle tabelle referenziate dalla vista. &lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/8816562946887277252/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/05/sql-server-2012-viste-problemi-e.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8816562946887277252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8816562946887277252'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/05/sql-server-2012-viste-problemi-e.html' title='SQL Server 2012 : Viste, problemi e soluzioni....'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXy4xSqFmm_nLn9jnuM4jknzONOYUzmL_QpX4wnhYTlj3D0nOqvsRBPY5vWGywUkVUF58x7ZmI4g-nK7dHsHBAeyb-5dn6H-xidoEIqCqQQU-qBNF57rbwKe5v0hs1lyJn_bzzAN57Mg0z/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-8853279550109989789</id><published>2013-03-21T17:32:00.004+01:00</published><updated>2013-03-21T17:32:41.318+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Jobs"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2008 R2"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2012"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server Express"/><title type='text'>SQL Server Express Edition : Schedulare jobs</title><content type='html'>Ok, &lt;a href=&quot;http://www.microsoft.com/en-us/sqlserver/editions/2012-editions/express.aspx&quot;&gt;SQL Server Express&lt;/a&gt; non ha il SQL Server Agent, ma questo non è una buona scusa per non implementare backup e attività di manutenzione regolari dei Database.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Anche senza SQL Server Agent è possibile, con un pizzico di lavoro in più, schedulare tutte le attività necessarie al mantenimento dei DB.&lt;br /&gt;
Come ? Usando lo &lt;a href=&quot;http://technet.microsoft.com/en-us/library/cc770904.aspx&quot;&gt;Schedule Task &lt;/a&gt;del sistema operativo e un poco di sano T-SQL !!&lt;br /&gt;
&lt;br /&gt;
Immaginiamo di voler fare un backup ed il rebuild degli indici del Db collegato a Sql Express&lt;br /&gt;
&lt;br /&gt;
Creo un DB di test di cui effettuare la manutenzione&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Master
Go

Create database TestJob
Go

Use TestJob
Go


create table TestTab
(
 id int
 ,campo varchar(25)
)

create clustered index idx on TestTab(id)
Go

;with cte as (Select 1 Riga union all Select 1)
 ,cte4 as (Select A.Riga From cte A, cte B)
 ,cte16 as (Select A.Riga From cte4 A, cte4 B)
 ,cte256 as(Select A.Riga From cte16 A, cte16 B)
 ,cte65536 as(Select A.Riga From cte256 A, cte256 B)
 ,results as(Select Row_number()Over(Order By Riga)Riga from cte65536)
Insert into TestTab 
Select Riga,riga from Results
Go 2
&lt;/pre&gt;&lt;br /&gt;
Verifichiamo subito se c&#39;è frammentazione per avere un raffronto post manutenzione.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use TestJob
Go
select * from sys.dm_db_index_physical_stats(db_id(),null,null,null,&#39;Detailed&#39;)
Go
&lt;/pre&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieh8OqhujWFmywsBEhRCL0wMWOczKCp21o0SY2mPWNAaSu8FVo0Xk8TWqEu1fU8CmomeA-M6LgiVPZp170r-MHmqDDil7hhXL6FoR3wxpkJiXA0d0HsNea-csdV2DMF260UpmiIthbhzz0/s1600/1.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieh8OqhujWFmywsBEhRCL0wMWOczKCp21o0SY2mPWNAaSu8FVo0Xk8TWqEu1fU8CmomeA-M6LgiVPZp170r-MHmqDDil7hhXL6FoR3wxpkJiXA0d0HsNea-csdV2DMF260UpmiIthbhzz0/s320/1.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Ok.... Frammentazione al 98% nella tabella...&lt;br /&gt;
&lt;br /&gt;
Mi serve poi un DB di Log all&#39;interno del quale salvare gli esiti delle operazioni pianificate.&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Master
Go

create database LogJob
Go

Use LogJob
Go

Create table TabLogJob
(
 Data datetime default getdate()
 ,Errore bit
 ,Messaggio varchar(max)
)
Go
&lt;/pre&gt;&lt;br /&gt;
Preparo uno Script di backup e di Rebuild degli indici.&lt;br /&gt;
Ovviamente il backup deve essere implementato post Check d&#39;integrità del database.&lt;br /&gt;
Quindi gli step sono&lt;br /&gt;
1: Check Integrity&lt;br /&gt;
2: Backup&lt;br /&gt;
3: Rebuild&lt;br /&gt;
&lt;br /&gt;
In caso d&#39;errore log nella tabella TabLogJob del DB LogJob&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use TestJob
Go

CREATE TABLE #DBCC_CHECKDB 
(   
 Error int NULL,
 [Level] int NULL,
 State int NULL,
 MessageText nvarchar(2048) NULL,
 RepairLevel nvarchar(22) NULL,
 Status int NULL,
 DbId int NULL,
 DbFragId int NULL,
 ObjectId int NULL,
 IndexId int NULL,
 PartitionId bigint NULL,
 AllocUnitId bigint NULL,
 RidDbId smallint NULL,
 RidPruId smallint NULL,
 [File] smallint NULL,
 Page int NULL,
 Slot int NULL,
 RefDbId smallint NULL,
 RefPruId smallint NULL,
 RefFile smallint NULL,
 RefPage int NULL,
 RefSlot int NULL,
 Allocation smallint NULL 
)    

INSERT INTO #DBCC_CHECKDB 
(
 Error,
 [Level], 
 State,
 MessageText,
 RepairLevel,
 Status,
 DbId,
 DbFragId,
 ObjectId,
 IndexId,
 PartitionId,
 AllocUnitId,
 RidDbId,
 RidPruId,
 [File],
 Page,
 Slot,
 RefDbId,
 RefPruId,
 RefFile,
 RefPage,
 RefSlot,
 Allocation
) 
EXEC(&#39;DBCC CHECKDB(TestJob) WITH TABLERESULTS, ALL_ERRORMSGS &#39;)   
If ( Select count(*) from #DBCC_CHECKDB Where Error &gt;= 8000 and level &gt;= 16 ) = 0  
Begin 
 
 begin try

  backup Database TestJob to disk = &#39;C:\SQL 2012\Backup\Full.bak&#39;
  Insert into LogJob.dbo.TabLogJob (Errore,Messaggio)
          values(0,&#39;Backup Effettuato Correttamente&#39;)

  exec sp_MSforeachtable &#39;ALTER INDEX ALL ON ? REBUILD&#39;
  Insert into LogJob.dbo.TabLogJob (Errore,Messaggio)
   values(0,&#39;Rebuild Effettuata Correttamente&#39;)

 end try
 begin catch

         Insert into LogJob.dbo.TabLogJob (Errore,Messaggio)
   Select 1,ERROR_MESSAGE()

 end catch
end
Else 
begin
 
 Insert into LogJob.dbo.TabLogJob (Errore,Messaggio)
 Select 1,MessageText from #DBCC_CHECKDB Where Error &gt;= 8000 and level &gt;= 16
 
end 
 
Drop table #DBCC_CHECKDB

&lt;/pre&gt;&lt;br /&gt;
Salvo lo script e mi preparo ad eseguirlo con l&#39;utility &lt;a href=&quot;http://msdn.microsoft.com/it-it/library/ms162773.aspx&quot;&gt;sqlcmd.exe&lt;/a&gt;.&lt;br /&gt;
Creo un file Batch contenente il seguente comando :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:c#&quot;&gt;
sqlcmd.exe -Slocalhost\SqlExpress -E -i&quot;C:\SQL 2012\Backup\Maintenance.sql&quot;

&lt;/pre&gt;&lt;br /&gt;
Provo il file e verifico se la frammentazione è calata e se nella tabella di Log è presente l&#39;avvenuta esecuzione&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use TestJob
Go
select * from sys.dm_db_index_physical_stats(db_id(),null,null,null,&#39;Detailed&#39;)
Go
&lt;/pre&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6ofBhZZFvluUUuBxwk-0OAXHIJ0lTCQLtJ1eLFoxseZMTTd83K90EOOTeitJ0Ixpr759Zjjn1GNKAcuOhGR0ra4NCig32f9FMxFL87PbYxcDaNP2ooB7DvPUcEgAsrBlHJFW17rfYGk0Z/s1600/8.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6ofBhZZFvluUUuBxwk-0OAXHIJ0lTCQLtJ1eLFoxseZMTTd83K90EOOTeitJ0Ixpr759Zjjn1GNKAcuOhGR0ra4NCig32f9FMxFL87PbYxcDaNP2ooB7DvPUcEgAsrBlHJFW17rfYGk0Z/s320/8.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Frammentazione inesistente....&lt;br /&gt;
&lt;br /&gt;
Verifico il Backup&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGIyy88KfxIAl1MfG9QNTFeIS1aXzJxDhD0Qtb7WQKxeV9NNuhL9Fu_v-6a1Pmx0jrvT9t0SFTCwH2wk4Zy0oS_1a1JKh8gXC79gZ4Rk0LDSFVy0_9n2YCHeWFcxiH4kz134tmrTNTBsCr/s1600/9.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGIyy88KfxIAl1MfG9QNTFeIS1aXzJxDhD0Qtb7WQKxeV9NNuhL9Fu_v-6a1Pmx0jrvT9t0SFTCwH2wk4Zy0oS_1a1JKh8gXC79gZ4Rk0LDSFVy0_9n2YCHeWFcxiH4kz134tmrTNTBsCr/s320/9.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Backup effettuato....&lt;br /&gt;
&lt;br /&gt;
Verifico il Log&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixSrz23mM_nckVdCxEARK2eAR7mUUUubLhUkv-cVDJzhZInyjxb50m8onuWkXaYefxAMdcLrHBbxbVPINFXzlp9kAvCWIbQuSP6rtsU6mKVjthUWbX4tAMs6IvZqc-gmUwjBj3W6Bwmg2o/s1600/10.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixSrz23mM_nckVdCxEARK2eAR7mUUUubLhUkv-cVDJzhZInyjxb50m8onuWkXaYefxAMdcLrHBbxbVPINFXzlp9kAvCWIbQuSP6rtsU6mKVjthUWbX4tAMs6IvZqc-gmUwjBj3W6Bwmg2o/s320/10.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Logging corretto !!!&lt;br /&gt;
&lt;br /&gt;
Perfetto !! Funziona tutto....&lt;br /&gt;
&lt;br /&gt;
Ora non mi resta che schedularlo per essere eseguito ogni giorno alle 16:45&lt;br /&gt;
&lt;br /&gt;
Step1 Creo il Task&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIESP2xTlMFUR6j8g3DEoe8t_EIDAVWHDdzobAgXlThflNW15xXoq1BSZ_aJMr20RYN63m_mqQUCADjk4u1-iYUl1Sx5sYsaDTT62qnH9qZn9W5OYsmn69MA65dLlpg6Ebw2COPZsY_5PB/s1600/2.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIESP2xTlMFUR6j8g3DEoe8t_EIDAVWHDdzobAgXlThflNW15xXoq1BSZ_aJMr20RYN63m_mqQUCADjk4u1-iYUl1Sx5sYsaDTT62qnH9qZn9W5OYsmn69MA65dLlpg6Ebw2COPZsY_5PB/s320/2.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Step2 Tipo di schedulazione&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirAGQ4rgNcNsBQaIZnm_0mU69cHhDMPnUvc_mmb2xMmRNeDgE-WeNyFYh8eLp1BNLaLdh40wSxUZI-MKCSouk8Bx1lgoYvrGHX-1ye_mPTdVWviQSOTCCs5MJsmzDKDR7ZLFpaRh1r8fqH/s1600/3.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirAGQ4rgNcNsBQaIZnm_0mU69cHhDMPnUvc_mmb2xMmRNeDgE-WeNyFYh8eLp1BNLaLdh40wSxUZI-MKCSouk8Bx1lgoYvrGHX-1ye_mPTdVWviQSOTCCs5MJsmzDKDR7ZLFpaRh1r8fqH/s320/3.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Step3 Seleziono l&#39;attività&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitlYRXLIBCzQhdSIvC9X5uFJG5gFB9vk1OHsCudxZ0QeyIAxTUgSFR5HryLQkzMhcgsPCuVYIvMqiXJBKTgCIkuSh-Z1V-bD5r3mCt6tmndjXyduHsOrnerHSFUtXZf0EXYRaqIABSTv1d/s1600/5.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitlYRXLIBCzQhdSIvC9X5uFJG5gFB9vk1OHsCudxZ0QeyIAxTUgSFR5HryLQkzMhcgsPCuVYIvMqiXJBKTgCIkuSh-Z1V-bD5r3mCt6tmndjXyduHsOrnerHSFUtXZf0EXYRaqIABSTv1d/s320/5.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Step4 Seleziono il batch&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQfQRCi6QR6zQerBHvG8Qw5YaKV1RusdI23VG1J6LHI82bWOt-0efXTgEDC5DHT06U-q8Ab64gM_UMFyKQkZdG9s8EGvMVoWSc3IhcK_Tga835l14Dp82vYQ2T3ujmhYKqufkE6hXlPYSo/s1600/4.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQfQRCi6QR6zQerBHvG8Qw5YaKV1RusdI23VG1J6LHI82bWOt-0efXTgEDC5DHT06U-q8Ab64gM_UMFyKQkZdG9s8EGvMVoWSc3IhcK_Tga835l14Dp82vYQ2T3ujmhYKqufkE6hXlPYSo/s320/4.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Step5 Imposto l&#39;ora di esecuzione&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDQTBVz5dpi3LoIOAYc8WUkYkinESSYThuWReMMJP1cvtLjji6JiNWUyv-BFuIzl6S7DU6pEdKU3Ba3BrwTYqk4dQqpJNuIkEeUHTqnHbU5SmAHn6VsbRq7RlLaWnBV2tH_79kdJgYCwC9/s1600/7.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDQTBVz5dpi3LoIOAYc8WUkYkinESSYThuWReMMJP1cvtLjji6JiNWUyv-BFuIzl6S7DU6pEdKU3Ba3BrwTYqk4dQqpJNuIkEeUHTqnHbU5SmAHn6VsbRq7RlLaWnBV2tH_79kdJgYCwC9/s320/7.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Step6 Finish con apertura eventuale delle proprietà per i setting relativi alla Security&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM-xXX18NScfA3DUVGMfspqjcf6hG5ybjwnBY2CrU1yIAOzq2EYnnvSDikb3YJ0bisP77LlWfKgdWsEh_NTYf8IZ2FkZCYGit7x9XPDoK7avrM0rma7IOYOeC3oqpiSnhyCYiB6TdE7J4L/s1600/6.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM-xXX18NScfA3DUVGMfspqjcf6hG5ybjwnBY2CrU1yIAOzq2EYnnvSDikb3YJ0bisP77LlWfKgdWsEh_NTYf8IZ2FkZCYGit7x9XPDoK7avrM0rma7IOYOeC3oqpiSnhyCYiB6TdE7J4L/s320/6.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Non mi resta che attendere le 16 e 45 per vedere se ha funzionato....&lt;br /&gt;
&lt;br /&gt;
tic tac... tic tac.... ;-)&lt;br /&gt;
&lt;br /&gt;
Ok... 16 e 45... Vediamo cosa è successo....&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-xRtdIFkWpTwHmDb1ToR-xK4-pdRYtnovzuVGkYOz0t_xU8Rik57AL8tjjGGR83ZhYZhuGWbvTL06cksGktM9K0oyI6XMce2ElmQBc41_w2fAS954VGAJY237E4VS7GGEgxKNkuCY2Us5/s1600/11.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-xRtdIFkWpTwHmDb1ToR-xK4-pdRYtnovzuVGkYOz0t_xU8Rik57AL8tjjGGR83ZhYZhuGWbvTL06cksGktM9K0oyI6XMce2ElmQBc41_w2fAS954VGAJY237E4VS7GGEgxKNkuCY2Us5/s320/11.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Ok, backup effettuato in append al file preesistente.....&lt;br /&gt;
&lt;br /&gt;
Verifico il Log&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc5ty20qVJlpV_9a9AGJ-dshXG6sMbaAs1zGzIrmE2ZQgRsDaPj2Rg72mz1X3jpJi76GtMfEg3lBnr3HZfdgNt4El8sBDukuD_sm8tuyr5x3rImR6pq1iLhFSDKcB58Ngi6RvBcNNO2v8k/s1600/12.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc5ty20qVJlpV_9a9AGJ-dshXG6sMbaAs1zGzIrmE2ZQgRsDaPj2Rg72mz1X3jpJi76GtMfEg3lBnr3HZfdgNt4El8sBDukuD_sm8tuyr5x3rImR6pq1iLhFSDKcB58Ngi6RvBcNNO2v8k/s320/12.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Log ok...&lt;br /&gt;
&lt;br /&gt;
Benissimo... I nostri DB ora saranno contenti !!!&lt;br /&gt;
&lt;br /&gt;
Immaginiamo però che a causa di errori del disco vi sia una datapage corrotta.&lt;br /&gt;
Ne danneggio una a caso....&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Alter Database TestJob set single_user with rollback immediate 
Go 
Dbcc writepage(TestJob,1,125,1,1,0x66,1) 
Go 
Alter Database TestJob set multi_user 
Go
&lt;/pre&gt;&lt;br /&gt;
Cosa accade se parte il batch ?&lt;br /&gt;
bhe... Parte la Dbcc checkdb() che restituisce errore,il backup e la rebuild non vengono implementati, e viene eseguito il log.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOUEobQv0Zu0_WXHr1ZZ6xxVYWgagJorhvWrtzf06iGBa-bR1a1Nd0rXoHWnTdxdw118nOs4eJXdtLPhLIEbOP1eDwnnHUJ9XbEFu6hgNKo4PatT5tRgOAgm90I3wyJpqHMy-ZHql3M1ue/s1600/14.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOUEobQv0Zu0_WXHr1ZZ6xxVYWgagJorhvWrtzf06iGBa-bR1a1Nd0rXoHWnTdxdw118nOs4eJXdtLPhLIEbOP1eDwnnHUJ9XbEFu6hgNKo4PatT5tRgOAgm90I3wyJpqHMy-ZHql3M1ue/s320/14.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Con poco sforzo si può modificare lo script in modo che crei un file di backup giornaliero e si può modificare il batch in modo che elimini i backup che non si desidera più mantenere on line....&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;OVVIAMENTE FARE IL BACKUP SULLA STESSA MACCHINA COME NEL MIO ESEMPIO NON E&#39; UNA BEST PRACTICE.&lt;br /&gt;
FARE IL BACKUP SULLA STESSA MACCHINA = NON FARE IL BACKUP !!!!&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca&lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/8853279550109989789/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/03/sql-server-express-edition-schedulare.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8853279550109989789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/8853279550109989789'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/03/sql-server-express-edition-schedulare.html' title='SQL Server Express Edition : Schedulare jobs'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieh8OqhujWFmywsBEhRCL0wMWOczKCp21o0SY2mPWNAaSu8FVo0Xk8TWqEu1fU8CmomeA-M6LgiVPZp170r-MHmqDDil7hhXL6FoR3wxpkJiXA0d0HsNea-csdV2DMF260UpmiIthbhzz0/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-343907997527296612</id><published>2013-03-07T18:06:00.001+01:00</published><updated>2013-03-28T10:58:11.264+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="LocalDb"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2012"/><title type='text'>SQL Server 2012 : LocalDB</title><content type='html'>Si sa dai....&lt;br /&gt;
Ai Dev non piace assolutamente configurare e manutenere un RDBMS... :-)&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/hh510202.aspx&quot;&gt;SQL Server 2012 LocalDb&lt;/a&gt; esaudisce i desideri degli sviluppatori...&lt;br /&gt;
Perché installare SQL Server Express per avere un servizio RDBMS se poi l&#39;utilizzo che ne si fa è saltuario e molto limitato ?&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
LocalDb è una modalità particolare d&#39;esecuzione di SQL Server Express rivolta agli sviluppatori per le attività di programmazione e debug ma che potrebbe essere anche utilizzata da applicazioni single user che necessitano di una base dati per poter funzionare. &lt;br /&gt;
Il vantaggio rispetto alla edizione SQL Server Express ?? &lt;br /&gt;
Bhè... L&#39;utilizzatore non deve preoccuparsi dell&#39;avvio del servizio, della configurazione etc...&lt;br /&gt;
&lt;br /&gt;
Se si sviluppa utilizzando Visual Studio 2012 viene installata automaticamente, altrimenti è necessario scaricare il &lt;a href=&quot;http://www.microsoft.com/en-us/download/details.aspx?id=29062&quot;&gt;setup&lt;/a&gt; ed eseguirne l&#39;installazione.&lt;br /&gt;
&lt;br /&gt;
Il Database poi sarà un vero e proprio DB Sql Server a tutti gli effetti. Sarà composto da file dati e file Log, potremo usare viste, stored procedure, functions, trigger etc...&lt;br /&gt;
&lt;br /&gt;
Ma le applicazioni come fanno a connettersi al Db se non ho a disposizione un&#39;istanza Express ? &lt;br /&gt;
Quando l&#39;applicazione che necessita dei dati invoca una connessione viene avviato un processo di SQL Server LocalDb che farà da &quot;gestore&quot; per il Db.&lt;br /&gt;
Quando poi l&#39;applicazione chiamante sarà chiusa dall&#39;utente, automaticamente, dopo qualche minuto verrà terminato anche il processo di SQL Server LocalDb.&lt;br /&gt;
&lt;br /&gt;
Vediamo un esempio.&lt;br /&gt;
&lt;br /&gt;
Utilizzando Visual Studio 2012 genero un nuovo progetto Windows form.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSPkstrg0JfNH-Ke5X0YPkTjNDXeyuKZ0LwSR1DKgQxpPZMAHFPayDi9HDE_ay3qM341zl3Eh8CYK7MFuW0OfQhJvxUFrQM22aBWJHlQ2ImpOKKrCMQ_rGQyXCLSCzoWEdstXS8x4HwiEJ/s1600/1.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSPkstrg0JfNH-Ke5X0YPkTjNDXeyuKZ0LwSR1DKgQxpPZMAHFPayDi9HDE_ay3qM341zl3Eh8CYK7MFuW0OfQhJvxUFrQM22aBWJHlQ2ImpOKKrCMQ_rGQyXCLSCzoWEdstXS8x4HwiEJ/s320/1.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Ho bisogno ora di creare un Db a cui la mia applicazione possa fare riferimento, quindi:&lt;br /&gt;
View-&gt;Sql Server Object Explorer&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxXSeFO5k0gyJ3w8-f224n9H2op8CZVsNu-n_Pn7D66-M-THy625fFlykaId1uVAcF_AVXpR2uMv1o5t8lgeAKui50twzpU2T-l5ahLLIe8iYMO-ewQK1eiH-r77q8Z1OZrfhyQEHPm1Fz/s1600/2.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxXSeFO5k0gyJ3w8-f224n9H2op8CZVsNu-n_Pn7D66-M-THy625fFlykaId1uVAcF_AVXpR2uMv1o5t8lgeAKui50twzpU2T-l5ahLLIe8iYMO-ewQK1eiH-r77q8Z1OZrfhyQEHPm1Fz/s320/2.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Il mio progetto ha già a disposizione un&#39;istanza su cui appoggiarsi per reperire i dati del Db. &lt;br /&gt;
L&#39;istanza si chiama (localdb)\Projetcs e viene creata con il setup di Visual Studio 2012 SSDT.&lt;br /&gt;
&lt;br /&gt;
Ora devo creare il Db, Tasto Dx sulla folder Databases e Add New Database&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnZM21zlhtqkG6uUuuAaW0r3sKw7kcP3ml-D5dLlKudHFG4-hAHuDro-APFAGaZ8ii9gvVBh5BMpdXGFqb-b11V-HeZXziZETUs5frORBGGTQfYBQ6gBCO0WNoTui3mbnIgZ3EAEld-x0G/s1600/3.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnZM21zlhtqkG6uUuuAaW0r3sKw7kcP3ml-D5dLlKudHFG4-hAHuDro-APFAGaZ8ii9gvVBh5BMpdXGFqb-b11V-HeZXziZETUs5frORBGGTQfYBQ6gBCO0WNoTui3mbnIgZ3EAEld-x0G/s320/3.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Devo solo specificare il nome e la locazione dei file *.mdf e *.ldf&lt;br /&gt;
&lt;br /&gt;
Ora devo generare la struttura delle tabelle, delle view, delle stored procedure etc... all&#39;interno del Db.&lt;br /&gt;
Tasto Dx su Tables e Add New Table&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbV1_twRjzGv3AT8aWIEKyuAOxvZLFGVCCnOZRqizH5_EbEn8twtC9C8QHOCQWSM_Dm7qC3nODNZmWBs4cWO8Q-5giuGbEbWeNj0val4igh3AVPpll77NM57Yaxeqzn4NfLG9tGFQPWvE4/s1600/4a.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbV1_twRjzGv3AT8aWIEKyuAOxvZLFGVCCnOZRqizH5_EbEn8twtC9C8QHOCQWSM_Dm7qC3nODNZmWBs4cWO8Q-5giuGbEbWeNj0val4igh3AVPpll77NM57Yaxeqzn4NfLG9tGFQPWvE4/s320/4a.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Una volta definita la struttura devo fare l&#39;Upload dell&#39;oggetto nel DB (tasto Upload in alto a sx) e mi appare una finestra di preview delle modifiche.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit2YjdOGu5wbB3Wk2SCyBrEiTKRQ6yB3UM_gRiP0dbTkb0WMKOg0VKbBoGifgpGvjLpEeSKE-FiG1tRCsouvQ3ANp4ltGY9OdglXyT3-ZTFrDD0fLRgExAK88n0mweWLV5JlsS07XHFViM/s1600/5.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit2YjdOGu5wbB3Wk2SCyBrEiTKRQ6yB3UM_gRiP0dbTkb0WMKOg0VKbBoGifgpGvjLpEeSKE-FiG1tRCsouvQ3ANp4ltGY9OdglXyT3-ZTFrDD0fLRgExAK88n0mweWLV5JlsS07XHFViM/s320/5.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Confermiamo l&#39;update e dell&#39;oggetto viene fatto il deploy nel DB.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2DVnnCfg6xfDpj9uTi6g_8GQ1CDfpxQuUMXUxHI4rlgxAQc0ZpcWxpmMjLInYH7YpaKiB5sIvvRAMsSXdLNthtOEWaIDJpkfU8jPJrW7SP-MrY_qaRhVz6RCxorYTLA2DUHnkRO-nxFoG/s1600/6.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2DVnnCfg6xfDpj9uTi6g_8GQ1CDfpxQuUMXUxHI4rlgxAQc0ZpcWxpmMjLInYH7YpaKiB5sIvvRAMsSXdLNthtOEWaIDJpkfU8jPJrW7SP-MrY_qaRhVz6RCxorYTLA2DUHnkRO-nxFoG/s320/6.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Possiamo anche inserire dei dati nella tabella appena creata&lt;br /&gt;
Tasto Dx sulla tabella Customers e View Data&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg01IzOIGTqXW_YcJT__2ERfoQuEpCvuhl2O5OyPbGsKsK5324lZsEMQdDHVbM5QztJI2_k2i7O6w5qXHYOu5v9nfwmWUbWwdVSxJV0zUsnIDip7njuTd_kCzQFY0zkUTbpuKa3q8IpapR8/s1600/7a.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg01IzOIGTqXW_YcJT__2ERfoQuEpCvuhl2O5OyPbGsKsK5324lZsEMQdDHVbM5QztJI2_k2i7O6w5qXHYOu5v9nfwmWUbWwdVSxJV0zUsnIDip7njuTd_kCzQFY0zkUTbpuKa3q8IpapR8/s320/7a.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Il nostro Db è ora pronto all&#39;uso !!!&lt;br /&gt;
&lt;br /&gt;
Se proprio si vogliono fare le cose in modo preciso sarebbe stato ottimale utilizzare un progetto di tipo SQL Server Database Project in modo da poter gestire il versioning degli oggetti etc...&lt;br /&gt;
&lt;br /&gt;
Ora possiamo occuparci dell&#39;applicazione Windows Form che dovrà leggere ed aggiornare i dati della tabella Customers.&lt;br /&gt;
Il codice dell&#39;applicazione lo potete trovare &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/fbk67b6z.aspx&quot;&gt;qui&lt;/a&gt;. E&#39; un esempio della msdn.&lt;br /&gt;
&lt;br /&gt;
L&#39;unica modifica che ho apportato è il salvataggio della connectionstring nell&#39;app.config dell&#39;applicazione.&lt;br /&gt;
Per il mio progetto in fase di debug sarà :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:xml&quot;&gt;&lt;appsettings&gt;
    &lt;add key=&quot;ConnectionString&quot; value=&quot;Data Source=(Localdb)\Projects; Integrated Security = SSPI; Initial Catalog = ApplicationDb&quot;/&gt;
  &lt;/appSettings&gt;
&lt;/pre&gt;&lt;br /&gt;
E qui dove la passo all&#39;applicazione per connettermi al DB e mostrare i dati&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:c#&quot;&gt;String connectionString = System.Configuration.ConfigurationManager.AppSettings[&quot;ConnectionString&quot;].ToString();
&lt;/pre&gt;&lt;br /&gt;
Proviamo ad eseguirla ed a leggere i dati dal nostro Db agganciato all&#39;istanza LocalDb\Projects&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFjl59daZ7gfELsUDKilnO2kr6LXA3cxHkoC2sE473hiE2iOEtKlDHoQUGSHtoukhyphenhyphenqeSz0E_wM_MHvH7S3cneWgYoa0CCABNr_eEMcwpaTmWZA2j3m15Am3SndLyamZPm6q96WrkfSCtq/s1600/8a.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFjl59daZ7gfELsUDKilnO2kr6LXA3cxHkoC2sE473hiE2iOEtKlDHoQUGSHtoukhyphenhyphenqeSz0E_wM_MHvH7S3cneWgYoa0CCABNr_eEMcwpaTmWZA2j3m15Am3SndLyamZPm6q96WrkfSCtq/s320/8a.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Inserisco una riga &lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE9oKOySLP7tYYtKKa2iRM-2SU6dRepNJgF7uWESCjFjmGenMXgvMI6y6BrgpBUfftG5hOgkHuv3xdOulHI5gZQaO1-vN0tOFduMIXx_SKSKU_oKx9kG0LdMGriIau1uw9butwPC2YshLN/s1600/9a.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE9oKOySLP7tYYtKKa2iRM-2SU6dRepNJgF7uWESCjFjmGenMXgvMI6y6BrgpBUfftG5hOgkHuv3xdOulHI5gZQaO1-vN0tOFduMIXx_SKSKU_oKx9kG0LdMGriIau1uw9butwPC2YshLN/s320/9a.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Perfetto... Funziona...&lt;br /&gt;
Ora la devo poter utilizzare su un&#39;altra macchina che non dispone ne di SQL Server ne di Visual Studio.&lt;br /&gt;
Come dicevo prima è necessario scaricare il package di &lt;a href=&quot;http://www.microsoft.com/en-us/download/details.aspx?id=29062&quot;&gt;setup&lt;/a&gt; del localDb ed eseguirlo sul client di destinazione&lt;br /&gt;
&lt;br /&gt;
Il secondo step è copiare l&#39;applicazione, i file del Db sul client ed infine configurare l&#39;app.config facendo in modo che utilizzi l&#39;istanza LocalDb&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:xml&quot;&gt;&lt;appsettings&gt;
    &lt;add key=&quot;ConnectionString&quot; value=&quot;Data Source=(Localdb)\v11.0; Integrated Security = SSPI; AttachDbFileName=C:\Users\Luca\Desktop\MyLocalDbApplication\ApplicationDb.mdf;Initial Catalog = ApplicationDb&quot;/&gt;
  &lt;/appSettings&gt;
&lt;/pre&gt;&lt;br /&gt;
Come vedete si fa riferimento all&#39;istanza (Localdb)\v11.0 e viene anche fornito il path al file mdf.&lt;br /&gt;
In questo modo viene avviato il processo di SQL Server LocalDb e viene creato il DB ApplicationDb agganciando il file mdf specificato.&lt;br /&gt;
&lt;br /&gt;
Eseguo l&#39;applicazione.&lt;br /&gt;
&lt;br /&gt;
Avendo copiato il db dalla macchina di sviluppo ho a disposizione anche le righe inserite a scopo di test.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqL15aZ4TuuWzgLjmEspPakUhz1grBlD2u7oyb4e5ZGiL6It3EoqdN8uBK9PujNYOFIvghQHCR0NGueEvU8h_4K5JvxjzJtE_OxFXd-Gg4VXs_uD05EzJp2hKstI5MlOt_dv-vHIzPjWYF/s1600/8.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqL15aZ4TuuWzgLjmEspPakUhz1grBlD2u7oyb4e5ZGiL6It3EoqdN8uBK9PujNYOFIvghQHCR0NGueEvU8h_4K5JvxjzJtE_OxFXd-Gg4VXs_uD05EzJp2hKstI5MlOt_dv-vHIzPjWYF/s320/8.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Ne inserisco una nuova&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhk4yabW787El1hkmgzwmehM29D0PgsAGfz0aeCfDp6SwSLAdV9_GSFQoyvqWp80cvTe3enRGzZ_xv0YYZaioHxd6j8gdcFgE9-Myd7VRPJiK3D5IiX7AN8HpuP75A7i1-c-FQWaZl4OO6R/s1600/9.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhk4yabW787El1hkmgzwmehM29D0PgsAGfz0aeCfDp6SwSLAdV9_GSFQoyvqWp80cvTe3enRGzZ_xv0YYZaioHxd6j8gdcFgE9-Myd7VRPJiK3D5IiX7AN8HpuP75A7i1-c-FQWaZl4OO6R/s320/9.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Sul Client, quando si apre la connessione al Db viene attivato un processo di sqlservr.exe&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2ourcGc5OttrR8qyaur82_2-WA1CgWPbKS3W1cuDRqzk0qRDESPriFJQN2I6w4hMl4lynMLsE0hyphenhyphen6ItdWrlOZHL8HRvbWxNldoESVK55p2Wo1LTXlBX9HEUWXszKKeffLDcDSLSORMG9z/s1600/10.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2ourcGc5OttrR8qyaur82_2-WA1CgWPbKS3W1cuDRqzk0qRDESPriFJQN2I6w4hMl4lynMLsE0hyphenhyphen6ItdWrlOZHL8HRvbWxNldoESVK55p2Wo1LTXlBX9HEUWXszKKeffLDcDSLSORMG9z/s320/10.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Il bello è che non ci si deve preoccupare della sua chiusura !!! Dopo pochi minuti dalla chiusura della connessione anche il processo sqlservr.exe sarà automaticamente terminato.&lt;br /&gt;
Penso che LocalDb sia un ottima opzione per quelle piccole applicazioni single user che vengono utilizzate saltuariamente. &lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca </content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/343907997527296612/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/03/sql-server-2012-localdb.html#comment-form' title='1 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/343907997527296612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/343907997527296612'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/03/sql-server-2012-localdb.html' title='SQL Server 2012 : LocalDB'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSPkstrg0JfNH-Ke5X0YPkTjNDXeyuKZ0LwSR1DKgQxpPZMAHFPayDi9HDE_ay3qM341zl3Eh8CYK7MFuW0OfQhJvxUFrQM22aBWJHlQ2ImpOKKrCMQ_rGQyXCLSCzoWEdstXS8x4HwiEJ/s72-c/1.PNG" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-5846831625117686523</id><published>2013-03-06T13:25:00.011+01:00</published><updated>2013-03-08T16:42:39.446+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Data Pages"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2005"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2008"/><category scheme="http://www.blogger.com/atom/ns#" term="Sql Server 2008 R2"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server 2012"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><category scheme="http://www.blogger.com/atom/ns#" term="Troubleshooting"/><title type='text'>SQL Server 2012 : Datapage Repair</title><content type='html'>A causa di errori del disco, del controller, sbalzi di tensione o altri casi particolari i dati contenuti nei DB potrebbero danneggiarsi e diventare inutilizzabili. Il problema è che potremmo non accorgerci del danno fino a che quei dati precisi non ci servono.&lt;br /&gt;
Cosa dobbiamo fare in questo malaugurato caso ?&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Dobbiamo ripristinare la/le data pages danneggiate, semplice no ?!?!&lt;br /&gt;
&lt;br /&gt;
Creo un DB di esempio e lo popolo...&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Master
Go

Create database RestorePage
Go

Alter database RestorePage Set Recovery Full
Go

Use RestorePage
Go

Create table DamagePage
(
 id int primary key clustered
 ,valoreA varchar(25)
)
Go

;With Cte as (Select 1 Riga Union all Select 1) 
 ,Cte4 as (Select A.Riga from Cte A, Cte B)  
 ,Cte16 as (Select A.Riga from Cte4 A, Cte4 B)  
 ,Cte256 as (Select A.Riga from Cte16 A, Cte16 B)  
 ,Results as (Select Row_Number() Over(Order by riga)Riga From Cte256) 
insert into DamagePage 
Select Riga
 , &#39;Valore &#39; + Cast(Riga as Varchar(5))  
from Results
Go
&lt;/pre&gt;&lt;br /&gt;
Simulo un&#39;attività di Backup composta da Backup Full e T-Log&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Backup database RestorePage to disk = &#39;C:\SQL 2012\Backup\BckFull.bak&#39; With compression
GO

Backup Log RestorePage to disk = &#39;C:\SQL 2012\Backup\Log1.trn&#39; With compression
GO

Backup Log RestorePage to disk = &#39;C:\SQL 2012\Backup\Log2.trn&#39; With compression
GO
&lt;/pre&gt;&lt;br /&gt;
Recupero l&#39;id pagina in cui risiede la riga con id 128&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Select *,sys.fn_PhysLocFormatter( %%Physloc%% ) from DamagePage
Where id = 128
Go
&lt;/pre&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1w83rbG7yGehR4QgRsPXHOeko055MNMT51SCUlZuLwzyks1L2XfzBPwM5TmCEALpKBpyozazmNMvYq-dc5yztWaF5D8Q5DBzvmZjHLyD33vqq1Yj1cz0Mf8vtHVLe4ebFWnILPcoGLSl0/s1600/1.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1w83rbG7yGehR4QgRsPXHOeko055MNMT51SCUlZuLwzyks1L2XfzBPwM5TmCEALpKBpyozazmNMvYq-dc5yztWaF5D8Q5DBzvmZjHLyD33vqq1Yj1cz0Mf8vtHVLe4ebFWnILPcoGLSl0/s320/1.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
Danneggio la data page contenente la riga con id = 128 &lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Alter Database RestorePage set single_user with rollback immediate
Go
Dbcc writepage(RestorePage,1,217,1,1,0x66,1)
Go
Alter Database RestorePage set multi_user
Go
&lt;/pre&gt;&lt;br /&gt;
Ok.... Il danno è fatto... &lt;br /&gt;
Come faccio ad accorgermene ?&lt;br /&gt;
&lt;br /&gt;
Se non uso strumenti di diagnosi me ne accorgo solo quando una applicazione deve reperire la riga con id 128 dalla tabella&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Select * from DamagePage
Where id = 128
Go
&lt;/pre&gt;&lt;br /&gt;
Otterrà questo errore &lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtDJLktgU-RHij_cqoz0TuqoHe4w14JJunf_MTjmT6MGEXnLG-LZh-1h-i3_IUaRA8DEBfI9IPEL_e8tJxDw3s4MfqAV1jcqkFHQ7W-RravB3K593VbKJghrBzf2FSXCJ0dMe_541aj1YM/s1600/2.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtDJLktgU-RHij_cqoz0TuqoHe4w14JJunf_MTjmT6MGEXnLG-LZh-1h-i3_IUaRA8DEBfI9IPEL_e8tJxDw3s4MfqAV1jcqkFHQ7W-RravB3K593VbKJghrBzf2FSXCJ0dMe_541aj1YM/s320/2.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Quindi cosa posso fare ora ?&lt;br /&gt;
Avendo i backup del Db posso fare il restore della singola data page corrotta&lt;br /&gt;
&lt;br /&gt;
Gli step da attuare sono&lt;br /&gt;
1. Restore della data page con il comando &lt;a href=&quot;http://msdn.microsoft.com/it-it/library/ms186858.aspx&quot;&gt;Restore&lt;/a&gt; lasciando il db in recovery(Il DB resta accessibile, solo la data page oggetto del restore è inaccessibile....)&lt;br /&gt;
2. &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms189606.aspx&quot;&gt;Backup del tail log&lt;/a&gt;&lt;br /&gt;
3. &lt;a href=&quot;http://msdn.microsoft.com/it-it/library/ms186858.aspx&quot;&gt;Restore &lt;/a&gt;di tutti i t-log backup necessari lasciando il db in recovery&lt;br /&gt;
4. &lt;a href=&quot;http://msdn.microsoft.com/it-it/library/ms186858.aspx&quot;&gt;Restore &lt;/a&gt;del tail-log backup riportando il db on line&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use master
Go

--Restore data page e DB in recovery
restore database [RestorePage] page=&#39;1:217&#39; from disk = &#39;C:\SQL 2012\Backup\BckFull.bak&#39; with norecovery
Go

--Backup del tail-log
backup log [RestorePage] to disk =  &#39;C:\SQL 2012\Backup\Tail_log.trn&#39; with No_truncate
Go

--Restore dei T-Log
restore log [RestorePage] from disk = &#39;C:\SQL 2012\Backup\Log1.trn&#39; with norecovery
Go

restore log [RestorePage] from disk = &#39;C:\SQL 2012\Backup\Log2.trn&#39; with norecovery
Go

--Restore del tail-log
restore log [RestorePage] from disk = &#39;C:\SQL 2012\Backup\Tail_log.trn&#39; 
Go
&lt;/pre&gt;&lt;br /&gt;
Riproviamo ora a reperire la riga con id 128 dalla tabella&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Select * from DamagePage
Where id = 128
Go
&lt;/pre&gt;&lt;br /&gt;
Come vedete il problema è risolto...&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7M1aZCyXh12MQ7wD_l5kqT0uPjfHvqQAY0lE2TeYn-h5f6hh-XL407MId5VM6-P8kV2NvvTGFEu9xY9bp2gTipHvhCv3IaK5wrYMmW6PQrth375OxGsRQsi35X0vdvtAlbdijGPclky2D/s1600/3.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7M1aZCyXh12MQ7wD_l5kqT0uPjfHvqQAY0lE2TeYn-h5f6hh-XL407MId5VM6-P8kV2NvvTGFEu9xY9bp2gTipHvhCv3IaK5wrYMmW6PQrth375OxGsRQsi35X0vdvtAlbdijGPclky2D/s320/3.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Semplicissimo vero ?? &lt;br /&gt;
Ma siamo certi che i nostri backup non contengano errori ? &lt;br /&gt;
Se il backup è perfettamente integro siamo in grado di risolvere il problema, altrimenti la questione si complica, e di parecchio....&lt;br /&gt;
Immaginiamo che il backup dell&#39;esempio precedente non fosse stato integro... Avremmo fatto il restore della data page già danneggiata, complicando ancora di più le cose....&lt;br /&gt;
&lt;br /&gt;
Cosa potremmo tentare allora ?&lt;br /&gt;
&lt;br /&gt;
Possiamo tentare di aggiustare il Db con il comando &lt;a href=&quot;http://msdn.microsoft.com/it-it/library/ms176064.aspx&quot;&gt;Dbcc CheckDb()&lt;/a&gt; che mette a disposizione 2 opzioni di &quot;riparazione&quot;&lt;br /&gt;
1. REPAIR_REBUILD &lt;br /&gt;
2. REPAIR_ALLOW_DATA_LOSS&lt;br /&gt;
L&#39;opzione REPAIR_FAST è mantenuta per retro compatibilità ma di fatto non implementa alcunché....&lt;br /&gt;
&lt;br /&gt;
Proviamo a ridanneggiare la data page con lo script usato poco fa e vediamo cosa accade se tentiamo di ripararla con la dbcc checkDb()&lt;br /&gt;
&lt;br /&gt;
Provo prima l&#39;opzione REPAIR_REBUILD che non comporta perdita di dati&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Alter Database RestorePage set single_user with rollback immediate
Go
dbcc checkdb(RestorePage,REPAIR_REBUILD )
Go
Alter Database RestorePage set multi_user
Go
&lt;/pre&gt;&lt;br /&gt;
Ed ecco il risultato&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVZSby_4b_DzKBcHNr0a22Uih3k5aDFJ6B74GCTz8g-irlKPqmLxIKsI7ZlMJ4b2dGn26Vi-LaHz0HQd9KhVeHUuMjg2jf5Xy6ZhbsbNxcgHajzMgDoSO0ybho-yKUKh7lRdzx97zwWEnY/s1600/4.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVZSby_4b_DzKBcHNr0a22Uih3k5aDFJ6B74GCTz8g-irlKPqmLxIKsI7ZlMJ4b2dGn26Vi-LaHz0HQd9KhVeHUuMjg2jf5Xy6ZhbsbNxcgHajzMgDoSO0ybho-yKUKh7lRdzx97zwWEnY/s320/4.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Non ha fatto nulla..... &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Proviamo con l&#39;opzione REPAIR_ALLOW_DATA_LOSS&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Alter Database RestorePage set single_user with rollback immediate
Go
dbcc checkdb(RestorePage,REPAIR_ALLOW_DATA_LOSS )with no_infomsgs
Go
Alter Database RestorePage set multi_user
Go
&lt;/pre&gt;&lt;br /&gt;
Ha corretto gli errori... benissimo !!!!&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrSD71RPi42bmm4pZxB-Avo_x3kDoBbDTGfz16cvDYwLUjFpqtfMVm0zAR5B0mdnTQY9bVSmZ4c1sYgAgbObzaz7F-YQdA4rl0py_q0n2oLJKJJakBn1JYE5-mClSlPdQdrlOcchHijE-W/s1600/5.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrSD71RPi42bmm4pZxB-Avo_x3kDoBbDTGfz16cvDYwLUjFpqtfMVm0zAR5B0mdnTQY9bVSmZ4c1sYgAgbObzaz7F-YQdA4rl0py_q0n2oLJKJJakBn1JYE5-mClSlPdQdrlOcchHijE-W/s320/5.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Proviamo a verificare se la ricerca della riga con id 128 funziona &lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvSzMRKcxom-7tWBiSfBfheIaER6VBXVqxarTly0XLftEz-QeLvCX79-xVzPb5fS9e4jd4PFtD0ca1sn864yCQF2cQBAJfgG33DLj8WUvPavtcO0FsxTs5gQNyuI2EpRosuJpmB9cWyiAg/s1600/6.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvSzMRKcxom-7tWBiSfBfheIaER6VBXVqxarTly0XLftEz-QeLvCX79-xVzPb5fS9e4jd4PFtD0ca1sn864yCQF2cQBAJfgG33DLj8WUvPavtcO0FsxTs5gQNyuI2EpRosuJpmB9cWyiAg/s320/6.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
In effetti la query funziona, ma non mi restituisce i dati perché per riparare la data page la dbcc checkdb() l&#39;ha definitivamente eliminata !!!&lt;br /&gt;
Addio integrita dei dati quindi.....&lt;br /&gt;
&lt;br /&gt;
Per evitare questi spiacevoli inconvenienti prima di ogni Backup full o differenziale è &lt;b&gt;indispensabile&lt;/b&gt; effettuare un&#39;operazione di diagnosi utilizzando la &lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/it-it/library/ms176064.aspx&quot;&gt;Dbcc CheckDb()&lt;/a&gt; che verifica l&#39;integrità strutturale, logica e fisica del Db.&lt;br /&gt;
&lt;br /&gt;
Se la diagnosi non evidenzia errori posso effettuare il backup, se invece vengono segnalate anomalie che senso ha fare il backup ?&lt;br /&gt;
Senza il check del Db faremmo il backup anche degli errori e un backup contenente errori non serve a nulla visto che il nostro obiettivo è di avere i db in piena efficienza.&lt;br /&gt;
&lt;br /&gt;
Se i nostri backup sono creati utilizzando i &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms187658.aspx&quot;&gt;maintenance plan&lt;/a&gt; possiamo avvalerci del Check Database Integrity Task ed eseguire il backup solo se il primo task si è concluso senza errori, magari inviando una mail in caso di esito negativo.....&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-qkUhuLiC6iu-VPiAJO6-XOB7YH2dQIlAmVQ5gp-HQiRDVt0t8Js3OFjkMroI-bo71QrQ6fwfWEiuvr4vg5r5Gw0devGL17Xq8F1FDG6qcqKGTRwz_XohwpM-QKfayNTGWK6eWFZBo4cz/s1600/7.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-qkUhuLiC6iu-VPiAJO6-XOB7YH2dQIlAmVQ5gp-HQiRDVt0t8Js3OFjkMroI-bo71QrQ6fwfWEiuvr4vg5r5Gw0devGL17Xq8F1FDG6qcqKGTRwz_XohwpM-QKfayNTGWK6eWFZBo4cz/s320/7.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Se il backup lo gestiamo attraverso il t-sql possiamo utilizzare questo script&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;CREATE TABLE #DBCC_CHECKDB
( 
 Error int NULL, 
 [Level] int NULL, 
 State int NULL, 
 MessageText nvarchar(2048) NULL, 
 RepairLevel nvarchar(22) NULL, 
 Status int NULL, 
 DbId int NULL, 
 DbFragId int NULL,  
 ObjectId int NULL, 
 IndexId int NULL, 
 PartitionId bigint NULL, 
 AllocUnitId bigint NULL, 
 RidDbId smallint NULL,  
 RidPruId smallint NULL, 
 [File] smallint NULL, 
 Page int NULL, 
 Slot int NULL, 
 RefDbId smallint NULL,  
 RefPruId smallint NULL, 
 RefFile smallint NULL,  
 RefPage int NULL, 
 RefSlot int NULL, 
 Allocation smallint NULL 
) 

INSERT INTO #DBCC_CHECKDB 
(
 Error,
 [Level],
 State,
 MessageText,
 RepairLevel,
 Status, 
 DbId,
 DbFragId,
 ObjectId,
 IndexId,
 PartitionId,
 AllocUnitId,
 RidDbId,
 RidPruId,
 [File],
 Page,
 Slot,
 RefDbId,
 RefPruId,
 RefFile,
 RefPage,
 RefSlot,
 Allocation 
)
EXEC(&#39;DBCC CHECKDB(RestorePage) WITH TABLERESULTS, ALL_ERRORMSGS &#39;)

If ( Select count(*) from #DBCC_CHECKDB Where Error &gt;= 8000 and level &gt;= 16 ) = 0
 Backup Database RestorePage To disk = &#39;C:\SQL 2012\Backup\BackupFull.bak&#39;
Else
 throw 50000,&#39;Errori!! Impossibile implementare il backup!!!&#39;,1

Drop table #DBCC_CHECKDB
&lt;/pre&gt;&lt;br /&gt;
NB: Lo script l&#39;ho creato per SQL Server 2012.&lt;br /&gt;
&lt;br /&gt;
Facciamo sempre un check dei nostri db, almeno prima dei backup full, se vogliamo evitare spiacevoli sorprese !!!&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/5846831625117686523/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/03/sql-server-2012-datapage-repair.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/5846831625117686523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/5846831625117686523'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/03/sql-server-2012-datapage-repair.html' title='SQL Server 2012 : Datapage Repair'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1w83rbG7yGehR4QgRsPXHOeko055MNMT51SCUlZuLwzyks1L2XfzBPwM5TmCEALpKBpyozazmNMvYq-dc5yztWaF5D8Q5DBzvmZjHLyD33vqq1Yj1cz0Mf8vtHVLe4ebFWnILPcoGLSl0/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-340233044008832767.post-2744465461260005506</id><published>2013-03-05T15:14:00.002+01:00</published><updated>2013-03-07T20:49:07.992+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DeadLock Monitoring"/><category scheme="http://www.blogger.com/atom/ns#" term="Extended Events"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance tuning"/><category scheme="http://www.blogger.com/atom/ns#" term="Troubleshooting"/><title type='text'>Sql Server 2012 : Extended Events. Cosa Sono ?</title><content type='html'>RIP &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms181091.aspx&quot;&gt;SQL server Profiler&lt;/a&gt;.. !?!?!?!?!?!?!?! Eh ?!?!?!?! Ma come !?!?!?!??!&lt;br /&gt;
Ebbene si, dopo anni di onoratissimo servizio anche per Sql Server Profiler è giunta l&#39;ora della meritata pensione...&lt;br /&gt;
Ma chi lo sostituirà !?!?! Gli &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/bb630282.aspx&quot;&gt;Extended Events&lt;/a&gt; !!!&lt;br /&gt;
Gli Extended Events sono stati introdotti sin dall&#39;edizione 2008 ma il loro utilizzo era un tantino macchinoso dato che nel Management studio 2008 non era presente nessun tool di configurazione e a meno che non si installasse questo &lt;a href=&quot;http://extendedeventmanager.codeplex.com/&quot;&gt;Addin&lt;/a&gt; la configurazione doveva essere implementata via T-SQL.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Ma cosa sono questi Extended Events (d&#39;ora in poi EE) ? Sono la nuova architettura che consente ai DBA di raccogliere una vastissima gamma di informazioni relative all&#39;Engine di SQL Server per operazioni di monitoring, debug e troubleshooting. &lt;br /&gt;
Sono molto facili da comprendere e da utilizzare e nel Management Studio di SQL 2012 è integrata anche la loro configurazione attraverso una comoda UI.&lt;br /&gt;
&lt;br /&gt;
Ma perché mettere in pensione SQL Server Profiler ? &lt;br /&gt;
Perché è molto invasivo e molto pesante mentre gli extended events sono estremamente leggeri e scalabili. &lt;br /&gt;
&lt;br /&gt;
A dirla tutta SQL Server profiler non va totalmente in pensione, resterà il tool di Trace e Replay per Analysis Services.&lt;br /&gt;
&lt;br /&gt;
Ma cosa posso implementare con gli EE ?&lt;br /&gt;
Praticamente tutto ciò che era implementabile con SQL Profiler....&lt;br /&gt;
&lt;br /&gt;
Facciamo un esempio.... Come identificare un problema di DeadLock con gli EE.&lt;br /&gt;
&lt;br /&gt;
Genero un DB di test su cui causerò un DeadLock&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use Master
Go

Create Database ExtEvnDb
Go

Use ExtEvnDb
Go

Create table Tab_A
(
 idA int
)
Go

Create table Tab_B
(
 idB int
)
Go

Insert into Tab_A values(1),(2),(3)
Insert into Tab_B values(4)
Go

Select * from Tab_A
Select * from Tab_B
Go
&lt;/pre&gt;&lt;br /&gt;
Prepariamo ora la sessione di monitoring utilizzando gli EE.&lt;br /&gt;
Dal management studio ci connettiamo all&#39;istanza di SQL che vogliamo monitorare e selezioniamo la folder Management, all&#39;interno della quale troviamo &lt;br /&gt;
il configuratore degli EE&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB3jMihFSchQfBm_58ujgM_KdVU8rXYAl8hOibndeNmEesy3myCw7g3xE4l0sifvRvNljJLZyRDEOTJoo_NgD9bi3Hd8Z6tEe5MlrMsWmIeLpElcAMXRylbBUeM-RUam4KtTwKRwpATDLd/s1600/1.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB3jMihFSchQfBm_58ujgM_KdVU8rXYAl8hOibndeNmEesy3myCw7g3xE4l0sifvRvNljJLZyRDEOTJoo_NgD9bi3Hd8Z6tEe5MlrMsWmIeLpElcAMXRylbBUeM-RUam4KtTwKRwpATDLd/s320/1.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBfMKhG8Y8EN95lA1yA-8ojmbO9PSK3vCFEARt1ZLDK23hK-j_h8Gg3B3vE29SFVhVlYCurEVJcKNA6AFluxEfcFFb_eXl4SAkr0M0lJcVLwV2UIivUyh3rpFNHXRh1H1Fj5WY65uy-u7r/s1600/2.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBfMKhG8Y8EN95lA1yA-8ojmbO9PSK3vCFEARt1ZLDK23hK-j_h8Gg3B3vE29SFVhVlYCurEVJcKNA6AFluxEfcFFb_eXl4SAkr0M0lJcVLwV2UIivUyh3rpFNHXRh1H1Fj5WY65uy-u7r/s320/2.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Nella page General del configuratore diamo un nome alla sessione, nel mio caso DeadLockMonitor.&lt;br /&gt;
Possiamo configurare se l&#39;event session deve essere avviata automaticamente allo start dell&#39;engine e/o al termine della configurazione.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPsbIPKKGZ0RDMHFOx8dQSkAcY2Z7a0mAHXvwrVVS2Kg9YYiLgRVykO7i3HHC25UwjOfJYvfKvWJnSNERQV6Qt5eYrnrgX2R6X1jMWiYsEhBStSxSJIV4SjMWqK5f76grBFo5Mwo06ge3b/s1600/3.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPsbIPKKGZ0RDMHFOx8dQSkAcY2Z7a0mAHXvwrVVS2Kg9YYiLgRVykO7i3HHC25UwjOfJYvfKvWJnSNERQV6Qt5eYrnrgX2R6X1jMWiYsEhBStSxSJIV4SjMWqK5f76grBFo5Mwo06ge3b/s320/3.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Nella page Events possiamo selezionare gli eventi necessari alla sessione di monitoring.&lt;br /&gt;
Un Event altro non è che un&#39;azione, un&#39;attività scatenata da un&#39;operazione all&#39;interno dell&#39;engine di SQL Server.&lt;br /&gt;
Utilizzando la textbox Event Library ricerchiamo gli eventi adeguati alle nostre necessità, digitando il nome dell&#39;evento stesso o parte di esso.&lt;br /&gt;
Per ogni evento selezionato il configuratore mette a diposizione una descrizione e la lista dei campi ad esso associati, cioè quali informazioni possiamo estrarre dall&#39;evento stesso.&lt;br /&gt;
Per monitorare un DeadLock ci possono essere utili i seguenti eventi:&lt;br /&gt;
1. xml_deadlock_report = Grafico che rappresenta il deadlock&lt;br /&gt;
2. lock_deadlock = Evento di deadlock&lt;br /&gt;
3. sql_batch_starting = Avvio di un batch T-Sql&lt;br /&gt;
4. sql_batch_completed = Conclusione di un batch T-Sql&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1gvNJjK85rb01YiEZNzbgXCgID3ePw58y6LjLBW0dzLOSIk3Ki7jegCk19lIf3esHlP5hedtZz6omZ-NOz3GcP7sS-hF8djUhWxHzbCCKi02gQG6_d3l4a87NVWgz_N3X_5tIkb_SZ4GC/s1600/4.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1gvNJjK85rb01YiEZNzbgXCgID3ePw58y6LjLBW0dzLOSIk3Ki7jegCk19lIf3esHlP5hedtZz6omZ-NOz3GcP7sS-hF8djUhWxHzbCCKi02gQG6_d3l4a87NVWgz_N3X_5tIkb_SZ4GC/s320/4.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Una volta selezionati gli Eventi necessari passiamo alla loro configurazione premendo il button Configure&lt;br /&gt;
Il tab Global Fields(Actions) consente di selezionare i campi che devono essere restituiti dall&#39;evento selezionato.&lt;br /&gt;
Per monitorare un DeadLock ci possono essere utili i seguenti campi:&lt;br /&gt;
1. client_app_name = Nome dell&#39;applicazione che si connette a SQL Server&lt;br /&gt;
2. event_sequence = Numero sequenziale che identifica l&#39;ordine delle operazioni &lt;br /&gt;
3. session_id = Id della sessione&lt;br /&gt;
4. transaction_id = Id della transazione&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhx_mktE0DS2U6Bq2MGgswIrnZt89sT8ncxBtvCAbY3D1_VinQR2Fq6OuozkRzD2zMYf37eHDRih-QLUKXHRZyHVSLTARnG0abwi7AqOZq599BZC67KmnC6xTDlG1KKb1-hM_59qhxObAA2/s1600/6.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhx_mktE0DS2U6Bq2MGgswIrnZt89sT8ncxBtvCAbY3D1_VinQR2Fq6OuozkRzD2zMYf37eHDRih-QLUKXHRZyHVSLTARnG0abwi7AqOZq599BZC67KmnC6xTDlG1KKb1-hM_59qhxObAA2/s320/6.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Possiamo poi filtrare quali eventi tracciare. Per esempio vogliamo monitorare gli eventi selezionati ma solo quelli che si verificano in un determinato Db o che nel testo del comando hanno una stringa particolare. &lt;br /&gt;
NB: Non impostare il filtro sull&#39;evento xml_deadlock_graph, lo perderemmo....&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9lOUlKnBCvIOZbYn1NT2VqpNmX_Z0SeBJ8O-vROKcmsGJFCGD_6dc23JqIKvZsY_egyevP-h0ogDXdhfx6rG1q3mCcu70bRXRtowMetcj8aKDUVQaiWYG8g34kU3o450nzDyZziu1PnW6/s1600/7.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9lOUlKnBCvIOZbYn1NT2VqpNmX_Z0SeBJ8O-vROKcmsGJFCGD_6dc23JqIKvZsY_egyevP-h0ogDXdhfx6rG1q3mCcu70bRXRtowMetcj8aKDUVQaiWYG8g34kU3o450nzDyZziu1PnW6/s320/7.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Nella page Data Storage configuriamo dove gli eventi debbano essere collezionati.&lt;br /&gt;
Un &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/bb630339.aspx&quot;&gt;target&lt;/a&gt; è un consumatore di eventi, una locazione contenente gli eventi che si sono verificati. Possiamo collezionare gli eventi su file, in un buffer etc... e possiamo avere più target per ogni sessione di EE.&lt;br /&gt;
Un target può processare gli eventi in modo Sincrono o Asincrono.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUEEbFNUUk_JVpKx1mCWU2p7mTmExR_WaKzeCLOGDPltRpYM_oeMrnyUS14wjgtsMaSEsdV5E6zePE2OOrYHXNbZ1Dea0h5H9Jhyr2w4ucv58rr2At5Q-45YkXHHM102SU8NZwTJo_ikSn/s1600/8.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUEEbFNUUk_JVpKx1mCWU2p7mTmExR_WaKzeCLOGDPltRpYM_oeMrnyUS14wjgtsMaSEsdV5E6zePE2OOrYHXNbZ1Dea0h5H9Jhyr2w4ucv58rr2At5Q-45YkXHHM102SU8NZwTJo_ikSn/s320/8.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
A questo punto la configurazione è terminata, Click su OK e l&#39;EE Session verrà avviata e comincerà a monitorare gli eventi selezionati.&lt;br /&gt;
NB: la session verrà avviata se abbiamo messo il flag di auto start nella configurazione.&lt;br /&gt;
In caso contrario click dx del mouse sulla sessione di EE e selezioniamo Start o Stop Session.&lt;br /&gt;
&lt;br /&gt;
Vediamo di causare un dead lock&lt;br /&gt;
Dal management studio apro 2 connessioni avendo cura di utilizzare la Keyword Application Name per simulare l&#39;accesso da parte di una applicazione utente. &lt;br /&gt;
La prima connessione si chiamerà Application_1, la seconda Application_2&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBWOEh_Fgu4eqNawDl7dOV9DX1-X7I1aTsF-I_vIvGbeVyqKF_5yEKYIywT9D6dmLEGXsGayFY7WAYokQvPvZ9tl3XApZc4x7PLCXPe2HhdDhg2BveU7vy-znSO1cjbl5B77zebUaAZxHD/s1600/9.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBWOEh_Fgu4eqNawDl7dOV9DX1-X7I1aTsF-I_vIvGbeVyqKF_5yEKYIywT9D6dmLEGXsGayFY7WAYokQvPvZ9tl3XApZc4x7PLCXPe2HhdDhg2BveU7vy-znSO1cjbl5B77zebUaAZxHD/s320/9.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Ecco il command di Application_1&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use [ExtEvnDb]
Go

Begin tran 

Update Tab_A set ida = idA + 10

--Eseguire la prima parte del command di application_2

Update Tab_B Set idb = idb + 10

--Eseguire la seconda parte del command di application_2

commit
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
mentre questo è il command di Application_2&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;Use [ExtEvnDb]
Go

Begin tran 

Update Tab_B Set idb = idb + 30

--Eseguire la seconda parte del command di application_1

Update Tab_A set ida = idA + 30

--DeadLock Error

commit
&lt;/pre&gt;&lt;br /&gt;
La seguenza di operazioni sarà:&lt;br /&gt;
1. Application_1 : Begin tran Update Tab_A set ida = idA + 10&lt;br /&gt;
2. Application_2 : Begin tran Update Tab_B Set idb = idb + 30&lt;br /&gt;
3. Application_1 : Update Tab_B Set idb = idb + 10&lt;br /&gt;
4. Application_2 : Update Tab_A set ida = idA + 30&lt;br /&gt;
&lt;br /&gt;
Ecco il DeadLock&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_F_6tmRFEGnSO1GlkO5HTHPI0I96OLoE-hIDfF1KtZ3O4okTb1DCVdyvlnc1u7qPFaFLU1QI6Z0eX3vZskSR9ZuDhnbLF9pf5vsAno7ggB5zpsqe29oQ8OxUSBFctfq67Y0NG043ycFN-/s1600/10.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_F_6tmRFEGnSO1GlkO5HTHPI0I96OLoE-hIDfF1KtZ3O4okTb1DCVdyvlnc1u7qPFaFLU1QI6Z0eX3vZskSR9ZuDhnbLF9pf5vsAno7ggB5zpsqe29oQ8OxUSBFctfq67Y0NG043ycFN-/s320/10.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Come facciamo a verificare la nostra session di EE per reperire le info relative al DeadLock?&lt;br /&gt;
Utilizzando management studio...&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv-JdkqWhp9e5L1UJvBpZbkh-LMBvnUFMdkSvtlEioeXwXoe3oeu82JgALvZGd5AyLL6nSKg3bCn8pEXW4NF84odaNA_Oy-qUGm0Ne37dGAYD7uqk2wBTMNOHVbqF8xkRQo8EjluS6XLUS/s1600/11.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv-JdkqWhp9e5L1UJvBpZbkh-LMBvnUFMdkSvtlEioeXwXoe3oeu82JgALvZGd5AyLL6nSKg3bCn8pEXW4NF84odaNA_Oy-qUGm0Ne37dGAYD7uqk2wBTMNOHVbqF8xkRQo8EjluS6XLUS/s320/11.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Ed ecco che si aprono gli eventi consumati dal target&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgNuZj2LHtNzDJTszDO-wjSdhjmeK-M-JKgb_WPLcnUwY70xB7KnO2q2Dx8hfeKFePK6iox07c1tpCP8A_kKMczq0iBNhsUlMwCx6vbBVLoUJtSpkIc5_RYQCNrSBbcF2eyGzCE0vaLsjP/s1600/12.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgNuZj2LHtNzDJTszDO-wjSdhjmeK-M-JKgb_WPLcnUwY70xB7KnO2q2Dx8hfeKFePK6iox07c1tpCP8A_kKMczq0iBNhsUlMwCx6vbBVLoUJtSpkIc5_RYQCNrSBbcF2eyGzCE0vaLsjP/s320/12.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
L&#39;evento lock_deadlock mi indica che si è verificato un deadlock e l&#39;evento xml_deadlock_graph mostra il grafico&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_z4N40HrlRSIUFW_XxfNEezT06GyiyP58wx_RgUvLHO8QNaTDOoxB2UcFaLCqamd7s7iwQbpsWCNERPE90j_fcklgcVFYYnjFwos5x9I2S86B7uF0AaQ2koQcgtv3rEShCvOoqBPsT5qB/s1600/13.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_z4N40HrlRSIUFW_XxfNEezT06GyiyP58wx_RgUvLHO8QNaTDOoxB2UcFaLCqamd7s7iwQbpsWCNERPE90j_fcklgcVFYYnjFwos5x9I2S86B7uF0AaQ2koQcgtv3rEShCvOoqBPsT5qB/s320/13.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Il grafico indica che la session id 53 è stata killata per risolvere un deadlock con la session id 51. (SQL fa il Kill della sessione per cui è più semplice effettuare il rollback, sostanzialmente fa il kill della transazione più piccola)&lt;br /&gt;
&lt;br /&gt;
Quale è il comando che ha scatenato il deadlock ?&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_7SxKuDuFmW-pRamc8fXxvL2h7kQtzuyx_8cVwEZN8CvfDiLcoZIMkbr9w8xRJvjfmZ0GTV70C3dvO4zs7WYb2rAUoPtWjGociICioH6LP3sMIckh9ofpnD2eFcHgm3vJm6TYG_A1efBE/s1600/14.PNG&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_7SxKuDuFmW-pRamc8fXxvL2h7kQtzuyx_8cVwEZN8CvfDiLcoZIMkbr9w8xRJvjfmZ0GTV70C3dvO4zs7WYb2rAUoPtWjGociICioH6LP3sMIckh9ofpnD2eFcHgm3vJm6TYG_A1efBE/s320/14.PNG&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Grazie agli eventi ed ai fields selezionati in fase di configurazione possiamo risalire alla sequenza di operazioni e alle applicazioni che hanno causato il deadlock.&lt;br /&gt;
&lt;br /&gt;
Così come con il profiler potevamo creare delle trace da inviare al cliente, lo stesso lo possiamo implementare con gli EE.&lt;br /&gt;
Generiamo lo script di configurazione da inviare al cliente ed il gioco è fatto....&lt;br /&gt;
Il cliente poi non farà altro che inviarci uno o più file *.xel che potremo leggere facendo drag &amp; drop in Management Studio.&lt;br /&gt;
&lt;br /&gt;
Possiamo attivare più session EE contemporaneamente e per ciascuna di esse selezionare Events, Actions, Filter e Targets personalizzati con un overhead per l&#39;engine di molto inferiore a quello che avremmo utilizzando SQL Trace o addirittura il SQL Server Profiler.&lt;br /&gt;
&lt;a href=&quot;http://www.sqlperformance.com/2012/10/sql-trace/observer-overhead-trace-extended-events&quot;&gt;Qui&lt;/a&gt; trovate un interessante post sull&#39;overhead dato da EE e SQL Server Profiler.&lt;br /&gt;
&lt;br /&gt;
Quindi buon troubleshooting con gli Extended Events !!!&lt;br /&gt;
&lt;br /&gt;
Ciao&lt;br /&gt;
&lt;br /&gt;
Luca&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tipsandtrickssqlserver.blogspot.com/feeds/2744465461260005506/comments/default' title='Commenti sul post'/><link rel='replies' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/03/sql-server-2012-extended-events.html#comment-form' title='0 Commenti'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/2744465461260005506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/340233044008832767/posts/default/2744465461260005506'/><link rel='alternate' type='text/html' href='http://tipsandtrickssqlserver.blogspot.com/2013/03/sql-server-2012-extended-events.html' title='Sql Server 2012 : Extended Events. Cosa Sono ?'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/09654078851901894871</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB3jMihFSchQfBm_58ujgM_KdVU8rXYAl8hOibndeNmEesy3myCw7g3xE4l0sifvRvNljJLZyRDEOTJoo_NgD9bi3Hd8Z6tEe5MlrMsWmIeLpElcAMXRylbBUeM-RUam4KtTwKRwpATDLd/s72-c/1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry></feed>