﻿<?xml version='1.0' encoding='UTF-8'?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>SQLServerCentral / Discuss Content Posted by Dinesh Priyankara / Article Discussions / Article Discussions by Author  / Reusing Identities / Latest Posts</title><generator>InstantForum.NET v2.9.0</generator><description>SQLServerCentral</description><link>http://www.sqlservercentral.com/Forums/</link><webMaster>notifications@sqlservercentral.com</webMaster><lastBuildDate>Thu, 23 May 2013 10:41:04 GMT</lastBuildDate><ttl>20</ttl><item><title>RE: Reusing Identities</title><link>http://www.sqlservercentral.com/Forums/Topic9858-108-1.aspx</link><description>&lt;P&gt;I am replying after a looooooooooooong time &lt;img src='images/emotions/smile.gif' height='20' width='20' border='0' title='Smile' align='absmiddle'&gt;&lt;/P&gt;&lt;P&gt;On the first method the author is using a not so optimized query.  He is using different methods in each queries (sub query vs outer join and Min vs top 1).  More than that,  Should we declare a variable, get the result into the variable and select the variable? &lt;/P&gt;&lt;P&gt;I tried with Left outer join and the results are really better.  (I tried with both statistics time and statistics IO ON)&lt;/P&gt;&lt;P&gt;Select top 1 t1.IDENTITYCOL + IDENT_INCR('OrderHeader') As NextIdentityValuefrom OrderHeader t1 Left Outer join OrderHeader t2ON T1.IDENTITYCOL+IDENT_INCR('OrderHeader')=t2.IDENTITYCOLWhere t2.IDENTITYCOL is null&lt;/P&gt;&lt;P&gt;This is the result:&lt;/P&gt;&lt;P&gt;SQL Server Execution Times:   CPU time = 0 ms,  elapsed time = 0 ms.&lt;/P&gt;&lt;P&gt;SQL Server Execution Times:   CPU time = 0 ms,  elapsed time = 0 ms.SQL Server parse and compile time:    CPU time = 0 ms, elapsed time = 2 ms.2210&lt;/P&gt;&lt;P&gt;Table 'OrderHeader'. Scan count 2210, logical reads 4450, physical reads 0, read-ahead reads 0.&lt;/P&gt;&lt;P&gt;SQL Server Execution Times:   CPU time = 26 ms,  elapsed time = 26 ms.SQL Server parse and compile time:    CPU time = 0 ms, elapsed time = 0 ms.&lt;/P&gt;&lt;P&gt;Later I introduced a variable to get the Indentity increment first the the results are even better&lt;/P&gt;&lt;P&gt;Declare @Increment intSelect @Increment= IDENT_INCR('OrderHeader')Select top 1 t1.IDENTITYCOL + @Increment As NextIdentityValuefrom OrderHeader t1 Left Outer join OrderHeader t2ON T1.IDENTITYCOL + @Increment = t2.IDENTITYCOLWhere t2.IDENTITYCOL is null&lt;/P&gt;&lt;P&gt;The results are slightly better:&lt;/P&gt;&lt;P&gt;SQL Server Execution Times:   CPU time = 0 ms,  elapsed time = 0 ms.&lt;/P&gt;&lt;P&gt;SQL Server Execution Times:   CPU time = 0 ms,  elapsed time = 0 ms.SQL Server parse and compile time:    CPU time = 0 ms, elapsed time = 2 ms.&lt;/P&gt;&lt;P&gt;SQL Server Execution Times:   CPU time = 0 ms,  elapsed time = 0 ms.2210&lt;/P&gt;&lt;P&gt;Table 'OrderHeader'. Scan count 2136, logical reads 4439, physical reads 0, read-ahead reads 0.&lt;/P&gt;&lt;P&gt;SQL Server Execution Times:   CPU time = 7 ms,  elapsed time = 7 ms.SQL Server parse and compile time:    CPU time = 0 ms, elapsed time = 0 ms.&lt;/P&gt;&lt;P&gt;Finally,  I changed the min into top 1.  the results are almost to my previous results:&lt;/P&gt;&lt;P&gt;SELECT top 1 IDENTITYCOL + IDENT_INCR('OrderHeader') As NextIdentityValueFROM OrderHeader t1WHERE IDENTITYCOL BETWEEN IDENT_SEED('OrderHeader') AND 32766     AND NOT EXISTS (SELECT * FROM OrderHeader t2        WHERE t2.IDENTITYCOL = t1.IDENTITYCOL + IDENT_INCR('OrderHeader'))&lt;/P&gt;&lt;P&gt;SQL Server Execution Times:   CPU time = 0 ms,  elapsed time = 0 ms.&lt;/P&gt;&lt;P&gt;SQL Server Execution Times:   CPU time = 0 ms,  elapsed time = 0 ms.SQL Server parse and compile time:    CPU time = 3 ms, elapsed time = 3 ms.2210&lt;/P&gt;&lt;P&gt;Table 'OrderHeader'. Scan count 2210, logical reads 4440, physical reads 0, read-ahead reads 0.&lt;/P&gt;&lt;P&gt;SQL Server Execution Times:   CPU time = 15 ms,  elapsed time = 26 ms.SQL Server parse and compile time:    CPU time = 0 ms, elapsed time = 0 ms.&lt;/P&gt;&lt;P&gt; &lt;/P&gt;&lt;P&gt; &lt;/P&gt;</description><pubDate>Tue, 01 Nov 2005 22:25:00 GMT</pubDate><dc:creator>G.R.Prithiviraj Kulasingham</dc:creator></item><item><title>RE: Reusing Identities</title><link>http://www.sqlservercentral.com/Forums/Topic9858-108-1.aspx</link><description>&lt;P&gt;&lt;FONT face=Tahoma&gt;Dinesh wrote:&lt;/FONT&gt;&lt;/P&gt;&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;&lt;P&gt;&lt;FONT face=Tahoma&gt;As per the output, there are 20086 logical reads and it has taken 200 ms for the first method. But in second method there are only 19 logical reads and the execution time is less considerable. &lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT face=Tahoma&gt;That’s why I selected to continue in my way. But there may be a side that I have not seen but you can see. So, try on this and see whether how this T-SQL solution suit for you. &lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;P&gt;&lt;FONT face=Tahoma&gt;Actually, I think that you are not considering two things:&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT face=Tahoma&gt;1. The overhead of creating a table of 30000 rows is much greater than the difference between the two queries. If you prefer to store this table permanently, you have to consider that it's size will be added to each backup and that you need to adjust the number of rows as more data will be added in the main table.&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT face=Tahoma&gt;2. The example from Books Online doesn't assume that the seed and the interval are 1, instead it determines them and this is the main cause of the many logical reads. Try:&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT face="Courier New"&gt;SELECT MIN(IDENTITYCOL) + 1 as NextIdentityValue&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;FROM OrderHeader t1WHERE IDENTITYCOL BETWEEN 1 AND 32766     AND NOT EXISTS (SELECT * FROM OrderHeader t2        WHERE t2.IDENTITYCOL = t1.IDENTITYCOL + 1)&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT face=Tahoma&gt;You will get only about 120 logical reads (instead of about 20000) and the execution time is much better.&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT face=Tahoma&gt;Razvan Socol&lt;/FONT&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma; mso-bidi-font-size: 12.0pt"&gt;&lt;?XML:NAMESPACE PREFIX = O /&gt;&lt;O&lt;img src='images/emotions/tongue.gif' height='20' width='20' border='0' title='Tongue' align='absmiddle'&gt;&gt;&lt;/P&gt;&lt;/O&lt;img src='images/emotions/tongue.gif' height='20' width='20' border='0' title='Tongue' align='absmiddle'&gt;&gt;&lt;/SPAN&gt;</description><pubDate>Wed, 18 Feb 2004 03:48:00 GMT</pubDate><dc:creator>Razvan Socol</dc:creator></item><item><title>RE: Reusing Identities</title><link>http://www.sqlservercentral.com/Forums/Topic9858-108-1.aspx</link><description>You can of course, and that is the right answer. Downside will be (or may be anyway!) blocking.Andyhttp://www.sqlservercentral.com/columnists/awarren/</description><pubDate>Fri, 07 Mar 2003 06:34:00 GMT</pubDate><dc:creator>Andy Warren</dc:creator></item><item><title>RE: Reusing Identities</title><link>http://www.sqlservercentral.com/Forums/Topic9858-108-1.aspx</link><description>&lt;font face='Verdana'&gt;Hi Andy,Why can’t we run this insertion process within a transaction?&lt;/font id='Verdana'&gt;Dinesh PriyankaraEdited by - Dinesh on 03/06/2003  9:17:45 PM</description><pubDate>Thu, 06 Mar 2003 21:03:00 GMT</pubDate><dc:creator>Dinesh Priyankara</dc:creator></item><item><title>RE: Reusing Identities</title><link>http://www.sqlservercentral.com/Forums/Topic9858-108-1.aspx</link><description>In a high volume environment, wouldnt you run into issues with two users trying to use (re-use) the same key?Andyhttp://www.sqlservercentral.com/columnists/awarren/</description><pubDate>Thu, 06 Mar 2003 05:03:00 GMT</pubDate><dc:creator>Andy Warren</dc:creator></item><item><title>RE: Reusing Identities</title><link>http://www.sqlservercentral.com/Forums/Topic9858-108-1.aspx</link><description>&lt;font face='Verdana'&gt;Hi Mike,&lt;/font id='Verdana'&gt;&lt;font face='Verdana'&gt;Actually what we want is, reuse removed identities. So, whatever the method, whether TOP 1 or MIN, you get desired result. But if you consider about performance, TOP 1 is better.&lt;/font id='Verdana'&gt;&lt;font color=blue&gt;[font=Verdana]Dinesh Priyankara[font=Verdana]&lt;/font id=blue&gt;mcp mcse mcsd mcdba</description><pubDate>Wed, 05 Mar 2003 20:58:00 GMT</pubDate><dc:creator>Dinesh Priyankara</dc:creator></item><item><title>RE: Reusing Identities</title><link>http://www.sqlservercentral.com/Forums/Topic9858-108-1.aspx</link><description>First: With a Clustered PK the data is *always* returned in the natual table order, so order by is not necessary.  Second: why do we need to get the min occurence, all we really care about is a missing ident right?  so just give me the first ident and I will be happy. </description><pubDate>Wed, 05 Mar 2003 12:24:00 GMT</pubDate><dc:creator>Michael R Schmidt</dc:creator></item><item><title>RE: Reusing Identities</title><link>http://www.sqlservercentral.com/Forums/Topic9858-108-1.aspx</link><description>&lt;font face='Tahoma'&gt;Hi Jeremy,I agree with you if the OrderHeader table has no index created with IDENTITY column. But as a general rule, we always create clustered or nonclustered unique index.If no indexes available, Of course you have to use one of your statements. Then there will be slight performance problems but still the method is the winner.Dinesh Priyankara&lt;/font id='Tahoma'&gt;mcp mcse mcsd mcdba</description><pubDate>Thu, 13 Feb 2003 08:21:00 GMT</pubDate><dc:creator>Dinesh Priyankara</dc:creator></item><item><title>RE: Reusing Identities</title><link>http://www.sqlservercentral.com/Forums/Topic9858-108-1.aspx</link><description>I don't think your second method is correct. You are looking for the lowest number in the first gap, correct? In that case you'll either have to add an ORDER BY clause to your TOP query, or use "SELECT Min(intNumber)" instead of the TOP clause. The point is that the only way to guarantee that results are ordered - and thus to guarantee that the TOP 1 clause delivers the lowest gap - is to add an order by clause.Of course, in practice, due to the clustered primary key on the Numbers table you might well witness the correct result every time you try it without the ORDER BY, but there's no certainty. This behaviour might change with differences in the clustered index on the other table, differences in paralellism, or changes in the underlying db engine in future SQL Server versions.I would either rewrite your method as:SELECT TOP 1 intNumber FROM OrderHeader     RIGHT OUTER JOIN tb_Numbers    ON tb_Numbers.intNumber = OrderHeader.intIDWHERE intID IS NULL AND intNumber &amp;lt; = (SELECT MAX(intID) FROM OrderHeader) ORDER BY tb_Numbers.intNumber- or -SELECT Min(intNumber)FROM OrderHeader     RIGHT OUTER JOIN tb_Numbers    ON tb_Numbers.intNumber = OrderHeader.intIDWHERE intID IS NULL AND intNumber &amp;lt; = (SELECT MAX(intID) FROM OrderHeader) It would be interesting to see if the differences in performance with these (IMHO) correct methods are still as large, and which of these two alternative methods would be the fastest.Jeremy</description><pubDate>Thu, 13 Feb 2003 07:28:00 GMT</pubDate><dc:creator>Jeremy</dc:creator></item><item><title>Reusing Identities</title><link>http://www.sqlservercentral.com/Forums/Topic9858-108-1.aspx</link><description>Comments posted to this topic are about the content posted at &lt;A HREF=http://www.sqlservercentral.com/columnists/dPriyankara/reuseidentities.asp&gt;http://www.sqlservercentral.com/columnists/dPriyankara/reuseidentities.asp&lt;/A&gt;</description><pubDate>Sat, 08 Feb 2003 00:00:00 GMT</pubDate><dc:creator>Dinesh Priyankara</dc:creator></item></channel></rss>