<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://community.ugiss.org/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>SQL Server &amp;amp; Delphi : Filtered Indexes</title><link>http://community.ugiss.org/blogs/sgovoni/archive/tags/Filtered+Indexes/default.aspx</link><description>Tags: Filtered Indexes</description><dc:language>it</dc:language><generator>CommunityServer 2007 SP2 (Debug Build: 20611.960)</generator><item><title>Webcast: Filtered Indexes and Statistics in SQL Server 2008</title><link>http://community.ugiss.org/blogs/sgovoni/archive/2010/12/22/webcast-filtered-indexes-and-statistics-in-sql-server-2008.aspx</link><pubDate>Wed, 22 Dec 2010 22:07:00 GMT</pubDate><guid isPermaLink="false">696bf4df-f0eb-4942-9326-ff40615b13e5:7981</guid><dc:creator>sgovoni</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://community.ugiss.org/blogs/sgovoni/rsscomments.aspx?PostID=7981</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://community.ugiss.org/blogs/sgovoni/commentapi.aspx?PostID=7981</wfw:comment><comments>http://community.ugiss.org/blogs/sgovoni/archive/2010/12/22/webcast-filtered-indexes-and-statistics-in-sql-server-2008.aspx#comments</comments><description>&lt;p&gt;Sul portale BEIT - MSDN/TechNet - è stato pubblicato un altro Webcast (in Italiano)&amp;nbsp;dedicato alle funzionalità rilasciate con la versione 2008 di SQL Server. Questa volta parleremo di Filtered Indexes and Statistics, ovvero la possibilità di specificare una clausola WHERE nei comandi CREATE INDEX e CREATE STATISTICS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Abstract&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Con SQL Server 2008 presentiamo gli indici e le statistiche filtrate: si tratta delle strutture che conosciamo già, a cui però viene applicato un criterio di filtro. In questo webcast parleremo prevalentemente dei primi, cercando di capire quando è conveniente utilizzarli e quando la loro applicazione può migliorare le performance delle query.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Webcast&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SQL Server 2008: Filtered Indexes [&lt;a href="http://www.microsoft.com/italy/beit/Generic.aspx?video=7ec7e450-f89c-4907-848e-c8ea12575aa3" target="_blank"&gt;view/download webcast&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ringrazio lo Sponsor, &lt;a href="http://www.techsmith.com/" target="_blank"&gt;TechSmith&lt;/a&gt;, che ci ha donato una licenza di &lt;a href="http://www.techsmith.com/camtasia.asp" target="_blank"&gt;Camtasia&lt;/a&gt;, ottimo software per registrare screencast e demo!&lt;/p&gt;
&lt;p&gt;Buona visione! ...e se è stato di vostro gradimento, votatelo.&lt;/p&gt;&lt;img src="http://community.ugiss.org/aggbug.aspx?PostID=7981" width="1" height="1"&gt;</description><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/Indexes/default.aspx">Indexes</category><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/Webcast/default.aspx">Webcast</category><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/SQL+Server+2008+R2/default.aspx">SQL Server 2008 R2</category><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/Filtered+Indexes/default.aspx">Filtered Indexes</category><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/Filtered+Statistics/default.aspx">Filtered Statistics</category></item><item><title>Filtered Indexes</title><link>http://community.ugiss.org/blogs/sgovoni/archive/2009/09/12/filtered-indexes.aspx</link><pubDate>Sat, 12 Sep 2009 14:02:00 GMT</pubDate><guid isPermaLink="false">696bf4df-f0eb-4942-9326-ff40615b13e5:6597</guid><dc:creator>sgovoni</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://community.ugiss.org/blogs/sgovoni/rsscomments.aspx?PostID=6597</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://community.ugiss.org/blogs/sgovoni/commentapi.aspx?PostID=6597</wfw:comment><comments>http://community.ugiss.org/blogs/sgovoni/archive/2009/09/12/filtered-indexes.aspx#comments</comments><description>&lt;p&gt;Con SQL Server 2008 fanno il loro debutto gli indici e le statistiche filtrare; sono le strutture che conosciamo già, a cui però viene applicato un criterio di filtro. In questo post parleremo degli indici filtrati, cercando di capire quando la loro applicazione può migliorare le performance delle query.&lt;/p&gt;
&lt;p&gt;Il comando CREATE INDEX può ora accettare la clausola WHERE utilizzata per specificare il criterio di filtro.&lt;/p&gt;
&lt;p&gt;Consideriamo, ad esempio, un indice standard definito su due colonne di una tabella (col_1 e col_2), l’ultimo livello (foglia) contiene la combinazione dei valori presenti nelle due colonne. Diversamente, se specifichiamo un criterio nella clausola WHERE del comando CREATE INDEX, per selezionare solo alcuni valori di una colonna, (ad esempio col_1 &amp;gt; 10) le righe che non soddisfano il criterio verranno ignorate, proprio durante la costruzione dell’indice, a prescindere dal valore contenuto nella seconda colonna. Il risultato è una struttura B-Tree più piccola in cui l’ultimo livello (foglia) contiene soltanto i dati che verificano il criterio specificato.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Utilizzo degli indici filtrati&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;La probabilità che il query optimizer scelga di utilizzare un indice filtrato è più alta quando il criterio specificato nella clausola WHERE della query è simile al criterio specificato nella clausola WHERE dell’indice.&lt;/p&gt;
&lt;p&gt;Consideriamo, ad esempio, la tabella &lt;em&gt;dbo.orderheader&lt;/em&gt; con la seguente struttura:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;use [tempdb];&lt;br /&gt;go&lt;/p&gt;
&lt;p&gt;if (object_id(&amp;#39;orderheader&amp;#39;, &amp;#39;U&amp;#39;) is not null)&lt;br /&gt;&amp;nbsp; drop table dbo.orderheader;&lt;br /&gt;go&lt;/p&gt;
&lt;p&gt;-- create table orderheader&lt;br /&gt;create table dbo.orderheader&lt;br /&gt;(orderid int identity(1, 1) not null,&lt;br /&gt;&amp;nbsp;orderdate datetime default getdate() not null,&lt;br /&gt;&amp;nbsp;ordernumber as (isnull(N&amp;#39;SO&amp;#39; + convert([nvarchar](23), [orderid], 0), N&amp;#39;*** error ***&amp;#39;)),&lt;br /&gt;&amp;nbsp;customerid int default 1 not null,&lt;br /&gt;&amp;nbsp;shipname varchar(20) default &amp;#39;name&amp;#39;,&lt;br /&gt;&amp;nbsp;shipaddress varchar(40) default &amp;#39;address&amp;#39;,&lt;br /&gt;&amp;nbsp;shipvia varchar(40) default &amp;#39;via&amp;#39;,&lt;br /&gt;&amp;nbsp;shipcity varchar(20) default &amp;#39;city&amp;#39;,&lt;br /&gt;&amp;nbsp;shipregion varchar(20) default &amp;#39;region&amp;#39;,&lt;br /&gt;&amp;nbsp;shippostalcode varchar(20) default &amp;#39;postal code&amp;#39;,&lt;br /&gt;&amp;nbsp;shipcountry varchar(20) default &amp;#39;country&amp;#39;,&lt;br /&gt;&amp;nbsp;-- delivery info&lt;br /&gt;&amp;nbsp;deliverydate datetime default (getdate() + datepart(ss, getdate())) not null,&lt;br /&gt;&amp;nbsp;deliverynote varchar(40)&lt;br /&gt;&amp;nbsp;primary key(orderid)&lt;br /&gt;);&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Assumiamo che solo pochi ordini abbiamo dei dati nella colonna &lt;em&gt;deliverynote&lt;/em&gt;, utilizzata dai clienti per segnalare eventuali particolarità relative alla consegna, ad esempio: “non consegnare il Lunedì pomeriggio”.&lt;/p&gt;
&lt;p&gt;Popoliamo la tabella &lt;em&gt;dbo.orderheader&lt;/em&gt; con 500.000 ordini cliente (per semplicità inseriamo solo la testata) di cui solo 500 (uno su 1000) con dati nella colonna note di consegna (&lt;em&gt;deliverynote&lt;/em&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;declare @i as int&lt;br /&gt;set @i = 0&lt;br /&gt;while (@i &amp;lt; 500000)&lt;br /&gt;begin&lt;br /&gt;&amp;nbsp; set nocount on&lt;/p&gt;
&lt;p&gt;&amp;nbsp; -- insert orderheader&lt;br /&gt;&amp;nbsp; insert into dbo.orderheader default values&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; if (@i % 1000) = 1&lt;br /&gt;&amp;nbsp; begin&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; update&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dbo.orderheader&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; set&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; deliverynote = &amp;#39;Not deliver the &amp;#39; + (select ltrim(rtrim(datename(weekday, getdate() + @i)))) + &amp;#39; afternoon&amp;#39;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; where&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (orderid = (select scope_identity()))&lt;br /&gt;&amp;nbsp; end&lt;/p&gt;
&lt;p&gt;&amp;nbsp; set @i = (@i + 1)&lt;br /&gt;&amp;nbsp; set nocount on&lt;br /&gt;end;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Vogliamo ora creare un indice appropriato per la seguente query di estrazione degli ordini cliente con note e data di consegna compresa tra il 12/09/2009 ed il 12/10/2009.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;create nonclustered index FIDX__orderheader_delivernote on dbo.orderheader&lt;br /&gt;(&lt;br /&gt;&amp;nbsp; deliverydate&lt;br /&gt;&amp;nbsp; , deliverynote&lt;br /&gt;)&lt;br /&gt;include&lt;br /&gt;(&lt;br /&gt;&amp;nbsp; ordernumber&lt;br /&gt;&amp;nbsp; , orderdate&lt;br /&gt;);&lt;br /&gt;go&lt;/p&gt;
&lt;p&gt;select&lt;br /&gt;&amp;nbsp; deliverydate&lt;br /&gt;&amp;nbsp; , ordernumber&lt;br /&gt;&amp;nbsp; , orderdate&lt;br /&gt;from&lt;br /&gt;&amp;nbsp; dbo.orderheader&lt;br /&gt;where&lt;br /&gt;&amp;nbsp; (deliverydate between &amp;#39;20090912&amp;#39; and &amp;#39;20091012&amp;#39;)&lt;br /&gt;&amp;nbsp; and (deliverynote is not null);&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Eseguiamo la query e analizziamo il piano di esecuzione e le statistiche di I/O, l’indice &lt;em&gt;FIDX__orderheader_delivernote&lt;/em&gt; precedentemente creato viene scelto dal query optimizer, per l’estrazione dei dati richiesti sono necessarie &lt;strong&gt;1168&lt;/strong&gt; letture.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://community.ugiss.org/blogs/sgovoni/SQL_Server/Execution_Plan/Filtered_Indexes_Img1.PNG"&gt;&lt;img src="http://community.ugiss.org/blogs/sgovoni/SQL_Server/Execution_Plan/Filtered_Indexes_Img1.PNG" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Statistiche di I/O:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;(194 row(s) affected)&lt;br /&gt;Table &amp;#39;orderheader&amp;#39;. Scan count 1, &lt;strong&gt;logical reads 1168&lt;/strong&gt;, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.&lt;/p&gt;
&lt;p&gt;Applichiamo ora un criterio di filtro all’indice &lt;em&gt;FIDX__orderheader_delivernote,&lt;/em&gt; aggiungiamo la clausola WHERE e&amp;nbsp;specifichiamo la condizione &amp;quot;&lt;em&gt;deliverynote is not null&lt;/em&gt;&amp;quot;. Così facendo, durante la costruzione dell’indice, verranno considerate soltanto le righe aventi una nota di consegna:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;drop index FIDX__orderheader_delivernote on dbo.orderheader;&lt;br /&gt;go&lt;/p&gt;
&lt;p&gt;create nonclustered index FIDX__orderheader_delivernote on dbo.orderheader&lt;br /&gt;(&lt;br /&gt;&amp;nbsp; deliverydate&lt;br /&gt;&amp;nbsp; , deliverynote&lt;br /&gt;)&lt;br /&gt;include&lt;br /&gt;(&lt;br /&gt;&amp;nbsp; ordernumber&lt;br /&gt;&amp;nbsp; , orderdate&lt;br /&gt;)&lt;br /&gt;&lt;strong&gt;where&lt;br /&gt;&amp;nbsp; (deliverynote is not null);&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Analizziamo di nuovo il piano di esecuzione e le statistiche di I/O per la stessa query di interrogazione, ma con l’indice filtrato:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://community.ugiss.org/blogs/sgovoni/SQL_Server/Execution_Plan/Filtered_Indexes_Img2.PNG"&gt;&lt;img src="http://community.ugiss.org/blogs/sgovoni/SQL_Server/Execution_Plan/Filtered_Indexes_Img2.PNG" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Statistiche di I/O:&lt;/p&gt;
&lt;p&gt;(194 row(s) affected)&lt;br /&gt;Table &amp;#39;orderheader&amp;#39;. Scan count 1, &lt;strong&gt;logical reads 5&lt;/strong&gt;, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.&lt;/p&gt;
&lt;p&gt;Confrontando i piani di esecuzione, osserviamo che il query optimizer, in entrambi i casi, sceglie di utilizzare l’indice &lt;em&gt;FIDX__orderheader_delivernote&lt;/em&gt; perché questo “copre” la query, utilizzando l’indice filtrato però&amp;nbsp;si è drammaticamente ridotto il numero di pagine lette.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusioni&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Quando è conveniente utilizzare un indice filtrato ? E’ conveniente quando il rapporto tra il numero delle righe interessate nel filtro (applicato all’indice) e il numero (totale) delle righe presenti nella tabella è basso.&lt;/p&gt;
&lt;p&gt;L’efficacia dell’indice filtrato sarà tanto maggiore quanto minore risulterà essere questo rapporto (nell&amp;#39;esempio trattato il rapporto è 500/500.000 = 0.001).&lt;/p&gt;
&lt;p&gt;Qualora più del 50% delle righe della tabella &lt;em&gt;dbo.orderheader&lt;/em&gt; avessero le note di consegna, la manutenzione dell’indice filtrato sarebbe molto più costosa rispetto alla manutenzione dell’equivalente indice standard e la scelta di utilizzarlo sarebbe sbagliata. Gli indici filtrati risultano meno performanti degli indici standard nelle operazioni di mantenimento (durante la modifica dei dati).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://community.ugiss.org/aggbug.aspx?PostID=6597" width="1" height="1"&gt;</description><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/Indexes/default.aspx">Indexes</category><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/Performance/default.aspx">Performance</category><category domain="http://community.ugiss.org/blogs/sgovoni/archive/tags/Filtered+Indexes/default.aspx">Filtered Indexes</category></item></channel></rss>