<?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: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-2021989930591302225</id><updated>2012-01-25T09:54:21.162-08:00</updated><category term='psexec'/><category term='Windows XP'/><category term='Visual Studio'/><category term='continuous integration'/><category term='finance'/><category term='Thinkpad'/><category term='RAID'/><category term='buildbot'/><category term='contracting'/><category term='CTEs'/><category term='wtf'/><category term='DBA tools'/><category term='RANK'/><category term='headphones'/><category term='audio'/><category term='SmartFTP'/><category term='co-working'/><category term='performance'/><category term='IronPython'/><category term='SSIS'/><category term='remote working'/><category term='sql server 2005'/><category term='float'/><category term='IBM'/><category term='scripting'/><category term='Windows Vista'/><category term='VMWare'/><category term='multiprocessing'/><category term='russia'/><category term='IO'/><category term='security'/><category term='UDF'/><category term='home theater'/><category term='Job Scheduler'/><category term='DENSE_RANK'/><category term='dts'/><category term='best practices'/><category term='affinity mask'/><category term='XML'/><category term='Kerberos'/><category term='DT_R8'/><category term='IIS'/><category term='User Access Control'/><category term='hiring'/><category term='tcp/ip'/><category term='clusters'/><category term='regular expressions'/><category term='T-SQL'/><category term='Resolver One'/><category term='.NET'/><category term='Excel'/><category term='SSDs'/><category term='Python'/><category term='string manipulation'/><category term='whitespace'/><category term='CLR'/><category term='pyodbc'/><category term='SQL Management Studio'/><category term='debugging'/><category term='Microstrategy'/><category term='bcp'/><category term='bulk insert'/><category term='sysinternals'/><category term='sql server 2008'/><category term='T20'/><category term='transactions'/><category term='sql server installation'/><category term='starbucks'/><category term='Notepad++'/><category term='JOINs'/><category term='off topic'/><category term='programming languages'/><category term='vbscript'/><category term='SQL_VARIANT'/><category term='OSQL'/><category term='DT_WSTR'/><category term='linked servers'/><category term='sql server 2000'/><category term='windows service'/><category term='notification services'/><category term='multithreading'/><category term='HP EVA'/><category term='indexing'/><category term='backups'/><category term='sql server'/><category term='tempdb'/><category term='SQLCMD'/><category term='Active Directory'/><category term='HTTP 400'/><category term='Management Studio'/><category term='career'/><category term='pstools'/><category term='SAN'/><category term='physical database design'/><category term='msdtc'/><category term='litespeed'/><category term='DATE'/><category term='data'/><category term='ftp'/><category term='replication'/><title type='text'>NYC DBA</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>92</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5712083849065634515</id><published>2012-01-19T07:31:00.000-08:00</published><updated>2012-01-19T07:33:34.171-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Management Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2008'/><title type='text'>Refreshing Intellisense in SQL Management Studio 2008</title><content type='html'>If you're like me, you create and drop a lot of tables while developing, and you may be getting annoyed with SQL Server Management Studio because it fills in the names of old tables while you're typing unless you hit Escape.  Turns out that refreshing the Intellisense cache is as easy as &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ctrl-Shift-R&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5712083849065634515?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5712083849065634515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5712083849065634515' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5712083849065634515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5712083849065634515'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2012/01/refreshing-intellisense-in-sql.html' title='Refreshing Intellisense in SQL Management Studio 2008'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-755129427906422979</id><published>2012-01-18T10:12:00.001-08:00</published><updated>2012-01-18T10:28:06.423-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyodbc'/><category scheme='http://www.blogger.com/atom/ns#' term='DATE'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>If your DATE comes through pyodbc as a unicode, it's probably the driver</title><content type='html'>File this under "should have been obvious."  I had a test script break today because I was trying to do date math on an object that wound up being a &lt;span&gt;unicode&lt;/span&gt; instead of a &lt;span&gt;date&lt;/span&gt;.  I had gotten the variable value from a pyodbc query against a SQL 2008 database table with a DATE column.  I knew that DATETIME columns came in as &lt;span&gt;datetime.datetime&lt;/span&gt; objects, but the DATE column came in as a &lt;span&gt;unicode&lt;/span&gt;, which seemed strange.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Turns out it's the ODBC driver.  Demo:&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;div style="position:relative;padding-bottom:0px;padding-left:3px;padding-right:3px;clear:both;padding-top:0px" id="ColorBandedcontent"&gt;&lt;div style="margin-left:12px" id="imcontent"&gt; &lt;div style="direction: ltr; font-size: 9pt; "&gt;In [78]: cnxn = pyodbc.connect("DSN=local&lt;span style="font-size: 12px; "&gt;;")&lt;/span&gt;&lt;p style="font-size: 12px; "&gt;&lt;/p&gt;&lt;p style="font-size: 12px; "&gt;In [79]: crsr = cnxn.execute("select cast('2012-01-01' as date) as bar")&lt;/p&gt;&lt;p style="font-size: 12px; "&gt;In [80]: r = crsr.fetchone()&lt;/p&gt;&lt;p style="font-size: 12px; "&gt;In [81]: type(r.bar)&lt;br /&gt;Out[81]: unicode&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;span &gt;Then, when switching to SQLNCLI10&lt;/span&gt;&lt;span style="font-size: 16px; "&gt;:&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="position:relative;padding-bottom:0px;padding-left:3px;padding-right:3px;clear:both;padding-top:0px" id="ColorBandedcontent"&gt;&lt;div style="margin-left:12px" id="imcontent"&gt; &lt;div style="direction: ltr; font-size: 9pt; "&gt;In  [96]: cnxn = pyodbc.connect("Driver={SQL Server Native Client  10.0};Server=localhost;Trusted_Connection=Yes;")  &lt;p&gt;&lt;/p&gt; &lt;p&gt;In [97]: crsr = cnxn.execute("select cast('2012-01-01' as date) as bar")&lt;/p&gt; &lt;p&gt;In [98]: r = crsr.fetchone()&lt;/p&gt; &lt;p&gt;In [99]: type(r.bar)&lt;br /&gt;Out[99]: datetime.date&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-755129427906422979?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/755129427906422979/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=755129427906422979' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/755129427906422979'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/755129427906422979'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2012/01/if-your-date-comes-through-pyodbc-as.html' title='If your DATE comes through pyodbc as a unicode, it&apos;s probably the driver'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8776249882580413381</id><published>2012-01-17T13:04:00.001-08:00</published><updated>2012-01-18T10:29:44.995-08:00</updated><title type='text'>Faster, thinner, lighter</title><content type='html'>It's almost time to retire my trusty old Dell E4300.  The warranty just expired, which means that if Dell has optimized their average component MTBF vs warranty span correctly, the laptop will implode shortly.  I replaced the original hard drive with a 2nd-gen Sandforce SSD a year ago, and it's made a big difference, but I'm ready for a little more speed.  And, with the advent of the "Ultrabook" form factor, for even less weight and size.  I've decided I want one.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At CES this year, there were plenty of ultrabooks on display - &lt;a href="http://www.engadget.com/2012/01/14/ces-2012-ultrabook-round-up/"&gt;Engadget's roundup&lt;/a&gt; has a few, more on &lt;a href="http://www.anandtech.com/show/5418/ces-2012-recap-the-week-in-review"&gt;Anandtech&lt;/a&gt;).  And most of them seemed to get at least some part of the formula right, but I don't think any of them have quite grabbed me yet.  Maybe I'm being picky, but I've decided that my top priorities are:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;- 1600 x 900 resolution&lt;/div&gt;&lt;div&gt;- Thunderbolt port (for docking)&lt;/div&gt;&lt;div&gt;- decent battery life (5 hrs+)&lt;/div&gt;&lt;div&gt;- light weight&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm sick of my current 1280 x 800 screen - the drop in my productivity from 2 big 1920 x 1080 screens down to the tiny laptop screen is painfully apparent.  1366 x 768 is arguably worse, since I really need those vertical lines of resolution.  And although I move around a lot with a laptop, which is why I want a good battery and light weight, I also use it as my primary workstation, so I need to be able to dock it and use my big monitors.  In fact, a laptop that would support 3 screens instead of 2 like my current Dell would be preferable.  Few of the ultrabooks seem to have this capability, but at least a Thunderbolt port would make it theoretically possible. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Other requirements are pretty normal.  The number of USB ports matters, but not hugely, since most peripherals I use at home while connected to a dock.  I do use my SD card reader pretty often, so it would be nice to keep that.  A decent keyboard, preferably backlit, would be useful.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Requirements in mind, I took a look at the current crop of ultrabooks just demoed at CES, and... was totally disappointed.  Nothing had all the features I wanted.  The closest ones were:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Samsung Series 9&lt;/div&gt;&lt;div&gt;- no Thunderbolt but both HDMI and DisplayPort connections&lt;/div&gt;&lt;div&gt;- 1600 x 900 resolution (on what I hear is a great screen)&lt;/div&gt;&lt;div&gt;- light weight (2.5 lbs)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sony Vaio Z&lt;/div&gt;&lt;div&gt;- Thunderbolt, sorta, via a proprietary connector as usual (thanks a lot, Sony)&lt;/div&gt;&lt;div&gt;- 1600 x 900&lt;/div&gt;&lt;div&gt;- light weight&lt;/div&gt;&lt;div&gt;- ungodly price ($1900+)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's &lt;a href="https://docs.google.com/spreadsheet/ccc?key=0AvB08HzkcCDFdEc3alF1bWczU1FDZk1lQ2g5TnZqc3c"&gt;my spreadsheet&lt;/a&gt; comparing the current crop of ultrabooks and their cousins using my completely biased and proprietary scoring system.  It's a definite work in progress and the scoring may change without warning.  If something comes along that scores above a 3, I'll probably buy it, but right now, none of these are worth the money.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8776249882580413381?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8776249882580413381/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8776249882580413381' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8776249882580413381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8776249882580413381'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2012/01/faster-thinner-lighter.html' title='Faster, thinner, lighter'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5781488385243380171</id><published>2012-01-04T23:00:00.001-08:00</published><updated>2012-01-04T23:16:27.201-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='DT_R8'/><category scheme='http://www.blogger.com/atom/ns#' term='DT_WSTR'/><title type='text'>More fun with SSIS type conversions</title><content type='html'>Just finished painfully debugging a strange SSIS issue about which I could find no documentation anywhere on the web, so I'm noting it here.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had changed a type within a large unwieldy data flow from DT_R4 (float) to DT_R8 (double), since the smaller data type was causing some weirdness around the least significant figures on some option prices.  This seemed to work in testing, but I got a cryptic error about a conditional operation failing during a derived column transformation when I deployed it to Production.  I opened the package, added an error redirection for the component and a data viewer, and sure enough, it was failing on a transformation that utilized some of the columns I had modified.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I couldn't find any reason why the conditional would fail, since it was faithfully spitting out BOOLs, but the resulting transformation split the float into Integer and Decimal by casting the value into a WSTR, 20 and then finding the decimal point.  After trying a dozen other things, I tried adjusting the size of the WSTR cast to a WSTR, 40.  That worked.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Note that the values that were failing would not even come close to 40 characters (ex: 110.68), but apparently the possibility of running into an overflow breaks something in the SSIS runtime.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, a word to the wise: if casting from float (DT_R4 or DT_R8) to Unicode string (WSTR), make sure you leave enough room to cast any possible value.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5781488385243380171?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5781488385243380171/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5781488385243380171' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5781488385243380171'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5781488385243380171'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2012/01/more-fun-with-ssis-type-conversions.html' title='More fun with SSIS type conversions'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-6078887109411144674</id><published>2011-12-22T07:28:00.000-08:00</published><updated>2011-12-22T07:39:42.776-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyodbc'/><category scheme='http://www.blogger.com/atom/ns#' term='multithreading'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='multiprocessing'/><title type='text'>pyodbc isn't playing well with multiprocessing</title><content type='html'>Wrote my first Python script yesterday that incorporates the multiprocessing module in order to parallelize some CPU-intensive calculations that were going extremely slowly when run in the database.  Mission accomplished there, and it was remarkably easy in Python, but then I hit a brick wall when trying to load everything back to the database.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As it turns out, the calculation time is dominated by the database IO (~25 mil rows in and out), so I went about trying to optimize that as best I could.  The reads are coming off an SSD, so they're fine, but the writes are UPDATEs, and I didn't want to issue them one at a time and incur all the connection and transaction overhead for each one.  Instead, I created a staging table as a heap and batched up INSERTs of my data in a specified batch size (1000 to start) using SQL 2008 row constructors.  Then the main table gets updated from the staging table right at the end, so only one giant transaction and UPDATE statement is necessary.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This strategy appeared to work fine when single-threading, but then I figured I'd throw in multiprocessing there, too, since I already had the module imported and had crafted the functions around it.  Didn't work.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The error message was 42S02, aka Invalid object specified - in other words, the INSERT can't find the staging table, even though I'm creating it within the Python script, during a single-threaded section before I Pool.map() out different calculated shards to be inserted.  SQL Server can obviously accept just about as many threads as you want to throw at it, so that's not the problem.  The table exists, which I confirmed by adding a breakpoint (well, a set_trace()) and looking at it through Management Studio.  It's all using integrated authentication, and I'm a sysadmin on the server, so there can't be any problems with schema, although I threw in some "dbo." references just to make sure.  I even tried to &lt;a href="http://msdn.microsoft.com/en-us/library/cc765421.aspx"&gt;trace the SQLNCLI driver operations&lt;/a&gt;, but haven't managed to get usable output yet.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So the only thing I can come up with so far is an incompatibility between pyodbc and multiprocessing.  If I get more time to investigate, I'll update the post, but for now I'm just going to have to switch the DB section back to single-threaded.  Boo.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-6078887109411144674?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/6078887109411144674/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=6078887109411144674' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6078887109411144674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6078887109411144674'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/12/pyodbc-isnt-playing-well-with.html' title='pyodbc isn&apos;t playing well with multiprocessing'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8663600526035886322</id><published>2011-11-30T07:00:00.000-08:00</published><updated>2011-11-30T07:02:56.723-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='string manipulation'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>SQL could use some real string manipulation</title><content type='html'>In order to remove the first "-" from a string, this is the query I just had to run:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;update tbFoo set BBG_ticker = substring(BBG_ticker, 1, charindex('-', BBG_ticker) - 1) + ' ' + substring(BBG_ticker, charindex('-', BBG_ticker)+1, LEN(BBG_ticker) - charindex('-', BBG_ticker))&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Does that seem like overkill to anyone else?  Let's compare it to Python...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;BBG_ticker.replace("-"," ",1)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8663600526035886322?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8663600526035886322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8663600526035886322' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8663600526035886322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8663600526035886322'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/11/sql-could-use-some-real-string.html' title='SQL could use some real string manipulation'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8144001178187476147</id><published>2011-10-22T09:20:00.000-07:00</published><updated>2011-10-22T09:34:04.113-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='remote working'/><title type='text'>Meeting new people in Laptopistan</title><content type='html'>This morning I'm back at Starbucks, as we haven't yet moved closer in to DC where there are alternatives to corporate coffee world, and I made the acquaintance of a woman who &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;1) made me explain the meaning of my &lt;a href="http://www.threadless.com/product/320/Rock_HOWTO"&gt;t-shirt&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;2) asked to use my laptop (instead of hers, for some reason?) to check her email&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;3) inquired about what I do for a living&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm pretty sure the next step will be to introduce me to her daughter/niece/granddaughter who's been looking for a nice Jewish boy (which I'm not, but I'm sure it wouldn't matter).  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Well, I suppose it's more interesting than doing R regressions while sitting at home.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8144001178187476147?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8144001178187476147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8144001178187476147' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8144001178187476147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8144001178187476147'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/10/meeting-new-people-in-laptopistan.html' title='Meeting new people in Laptopistan'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-6530259087668504971</id><published>2011-10-14T06:43:00.001-07:00</published><updated>2011-10-14T07:06:19.206-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='remote working'/><category scheme='http://www.blogger.com/atom/ns#' term='contracting'/><title type='text'>Life as a contractor</title><content type='html'>It's my own fault that I'm a contractor and not a full employee - a year ago, my girlfriend decided to go back to school in another state, and I followed her there.  My office was gracious (desperate?) enough to keep me on as a remote employee, but I was converted to contractor status, for both employment flexibility (i.e. they can let me go easily if it doesn't work out) and tax liability purposes.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For the most part, this has worked out fine.  Working from home can be a double-edged sword, but the non-existent commute is great and the ability to work from alternate locations seamlessly has been pretty nice - this summer we picked up and moved to Denver for 10 weeks with no interruption of my work, only a slight shift in working hours due to the time zone change.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But there are some definite drawbacks.  My taxes are far more complicated now, I don't get employer-sponsored health insurance, and there's a bit of a disconnect from the rest of my team and the firm at large.  This is both practical - I have difficulty hearing what's going on in many of my meetings, since I'm the only one on the phone instead of there in person - and psychological. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The latest case in point, and the catalyst for this post, occurred this morning.  The chairman of my firm sent out an email announcing a minor contest sort of thing in which employees can win an electronic gizmo that shall remain nameless in exchange for updating their employee profile.  I dutifully went to update mine, which I hadn't looked at since I was a Full-Time Employee... and found that I no longer have one.  This is far from a big deal, but it's a reminder of the fact that although I work like an employee (I'm on a fixed rate, not an hourly one), consider myself part of the firm, and try to act in its best interest, there's a psychic distance between me and the Real Employees.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are more examples.  The firm celebrated its 20th birthday a short time ago, and Employees all received small gift bags.  It should probably go without saying that I did not.  On one's 5th anniversary as an Employee, one receives a very small token of acknowledgement of service to the firm. My 5th year is coming up, but I presume it will be &lt;i&gt;sans&lt;/i&gt; token.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I assume this would be different at firms in which contracting is more widespread - contractors would be held either closer or farther away - but my situation is unusual at my office, so it's not worth HR's time to hold my hand through any weird episodes.  Also, these are minor enough issues that I would feel ridiculous complaining about them in person, so I'm using this medium to work through them a little.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, I know that my blog is occasionally perused by people from my office, so let me reiterate that this is &lt;b&gt;not a big deal &lt;/b&gt;and not intended to be a passive-aggressive complaint, it's just some musings on this strange state of employment that I, and a growing number of others, find myself in.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-6530259087668504971?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/6530259087668504971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=6530259087668504971' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6530259087668504971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6530259087668504971'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/10/life-as-contractor.html' title='Life as a contractor'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-7337082195233579249</id><published>2011-10-05T06:16:00.000-07:00</published><updated>2011-10-05T06:34:27.201-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='bcp'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='bulk insert'/><title type='text'>Loading Fixed Width files with BCP / Bulk Insert</title><content type='html'>I had to craft some format files in order to load a couple of fixed width files using the SQL Server BULK INSERT / bcp tools, and had some issues with the documentation when trying to get them to work.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So let me state this explicitly: when attempting to load a file with no line breaks, you do not need a terminator for any field in your format file.  Just specify all the field lengths, set the xsi:type to CharFixed, and the whole thing should stream in.  Ex:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;span style="color:#a65700; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#5f5035; "&gt;record&lt;/span&gt;&lt;span style="color:#a65700; "&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a65700; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#5f5035; "&gt;field&lt;/span&gt; &lt;span style="color:#274796; "&gt;id&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;1&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;type&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;CharFixed&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;length&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;12&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#a65700; "&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a65700; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#5f5035; "&gt;field&lt;/span&gt; &lt;span style="color:#274796; "&gt;id&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;2&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;type&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;CharFixed&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;length&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;3&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#a65700; "&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a65700; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#5f5035; "&gt;field&lt;/span&gt; &lt;span style="color:#274796; "&gt;id&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;3&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;type&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;CharFixed&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;length&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;5&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#a65700; "&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a65700; "&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#5f5035; "&gt;record&lt;/span&gt;&lt;span style="color:#a65700; "&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a65700; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#5f5035; "&gt;row&lt;/span&gt;&lt;span style="color:#a65700; "&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a65700; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#5f5035; "&gt;column&lt;/span&gt; &lt;span style="color:#274796; "&gt;source&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;1&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;name&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;series&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;type&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;SQLCHAR&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#a65700; "&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a65700; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#5f5035; "&gt;column&lt;/span&gt; &lt;span style="color:#274796; "&gt;source&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;2&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;name&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;pool&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;type&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;SQLCHAR&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#a65700; "&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a65700; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#5f5035; "&gt;column&lt;/span&gt; &lt;span style="color:#274796; "&gt;source&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;3&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;name&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;deal&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#274796; "&gt;type&lt;/span&gt;&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;SQLCHAR&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;"&lt;/span&gt; &lt;span style="color:#a65700; "&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a65700; "&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#5f5035; "&gt;row&lt;/span&gt;&lt;span style="color:#a65700; "&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can still mix and match - have a terminator for the last field in each line, for example - but if your file has 0 line breaks, you don't need it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also, the easiest way I found to handle skipping columns was to use OPENROWSET(BULK).  Just make sure you're selecting the names of the columns from the ROW section of the format file, not the RECORD section.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;i.e.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;span style="color:#800000; font-weight:bold; "&gt;SELECT&lt;/span&gt; series&lt;span style="color:#808030; "&gt;,&lt;/span&gt; deal &lt;span style="color:#800000; font-weight:bold; "&gt;FROM&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#800000; font-weight:bold; "&gt;OPENROWSET&lt;/span&gt;&lt;span style="color:#808030; "&gt;(&lt;/span&gt;&lt;span style="color:#800000; font-weight:bold; "&gt;BULK&lt;/span&gt; &lt;span style="color:#0000e6; "&gt;'source.txt'&lt;/span&gt;&lt;span style="color:#808030; "&gt;,&lt;/span&gt;&lt;br /&gt;FORMATFILE&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;'sample.xml'&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#808030; "&gt;)&lt;/span&gt; &lt;span style="color:#800000; font-weight:bold; "&gt;as&lt;/span&gt; x&lt;span style="color:#808030; "&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The documentation covers that part a bit better, but just wanted to reproduce it for my own sake, since I'm sure I'll forget how I did it between now and the next time I use BULK INSERT a few years from now.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;P.S. Gotta throw in a plug for &lt;a href="http://tohtml.com/"&gt;tohtml.com&lt;/a&gt; here for making my code actually paste into Blogger and look decent to boot.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-7337082195233579249?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/7337082195233579249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=7337082195233579249' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7337082195233579249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7337082195233579249'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/10/loading-fixed-width-files-with-bcp-bulk.html' title='Loading Fixed Width files with BCP / Bulk Insert'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-6652251801663162429</id><published>2011-10-05T06:08:00.000-07:00</published><updated>2011-10-05T06:16:07.736-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='remote working'/><title type='text'>Laptopistan upgrade</title><content type='html'>3G vs 4G tethering: night and day.  I can now click on things through my remote desktop session and have them actually respond, instead of doing the mental 2-count (or switching to Google Reader while waiting, which is always a productivity killer).  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have some concerns about the battery life of my new HTC Thunderbolt, and I'm not blown away by the form factor, but so far I definitely prefer it to my iPhone 3GS.  And the 4G factor alone makes it totally worthwhile.  &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-6652251801663162429?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/6652251801663162429/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=6652251801663162429' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6652251801663162429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6652251801663162429'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/10/laptopistan-upgrade.html' title='Laptopistan upgrade'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1221968162164496139</id><published>2011-08-23T09:40:00.000-07:00</published><updated>2011-08-23T09:44:18.400-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='msdtc'/><title type='text'>SSIS, MSDTC, and SQL Server clusters</title><content type='html'>Note to self: when receiving the following error from an SSIS package, the first thing to check is the Authentication setting for MSDTC.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;Description: The SSIS Runtime has failed to enlist the OLE DB connection in a distributed transaction with error 0x8004D00E "The transaction has already been implicitly or explicitly committed or aborted".&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The security setting should be set to No Authentication Required.  Mutual does not appear to work with clusters.  This is especially significant if, like me, you have a non-clustered instance in QA and a clustered one in Prod and you have been beating your head against the wall trying to figure out why MSDTC, with all the same settings, works in the former but not the latter.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1221968162164496139?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1221968162164496139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1221968162164496139' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1221968162164496139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1221968162164496139'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/08/ssis-msdtc-and-sql-server-clusters.html' title='SSIS, MSDTC, and SQL Server clusters'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-4529317044506002938</id><published>2011-07-01T15:31:00.000-07:00</published><updated>2011-07-02T11:01:30.238-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Excel'/><title type='text'>The Query Did Not Run</title><content type='html'>Why thank you, Excel, that's a very helpful error message.  Except I was watching the query execute on SQL Server, and it DOES run.  Perhaps there could be a different problem?&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The actual, exact text of the error is&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;The query did not run, or the database table could not be opened.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The sheet in question was running a stored procedure, which had been working fine, albeit very slowly.  A coworker tuned the proc and happened to use a temp table to accumulate the results for multiple queries instead of a UNION, producing better execution plans for each.  However, despite being 4x faster, the proc stopped running from Excel, throwing the error message above.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At first I thought there might be a problem with the final DROP #table statement in the proc, so I removed that.  No help.  I adjusted various properties of the database connection from Excel.  No change.  I fiddled with the table setup in Excel.  Nothing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then I remembered that I had some difficulties with pyodbc a while back that were resolved by setting NOCOUNT ON in the query.  I can't recall the exact cause, but it's something about the driver seeing the first count returned as the query result, when of course it's not in a proc that populates a table with a few queries and then selects from it as the final step.  Anyway, I set NOCOUNT ON at the beginning of the proc and OFF at the end and voila, it worked.  So try that if you're having difficulties with Excel not executing your stored proc correctly.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-4529317044506002938?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/4529317044506002938/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=4529317044506002938' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4529317044506002938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4529317044506002938'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/07/query-did-not-run.html' title='The Query Did Not Run'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-6314982227614532998</id><published>2011-06-21T11:14:00.000-07:00</published><updated>2011-06-21T11:32:30.904-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL_VARIANT'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>So you've got a problem, and you want to solve it using SQL_VARIANT</title><content type='html'>Now you've got a bigger problem, because using SQL_VARIANT for anything is a terrible idea. It's a memory and storage hog, it generally can't be indexed, it produces inconsistent and unpredictable behavior in code, and it's not supported by most client libraries.  Don't use it.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Of course, you may not have a choice, if some esteemed predecessor has implemented database structures with it.  In that case, you should definitely read up on it, but I just wanted to throw out one particularly useful function that I encountered yesterday while tearing my hair out trying to solve a problem with our resident SQL_VARIANT infection.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;CREATE TABLE dbo.tbFoo (&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;ID INT IDENTITY(1,1), &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;bar SQL_VARIANT)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That function would be SQL_VARIANT_PROPERTY().  The primary use of this function is to get the BaseType of the SQL_VARIANT column or variable, as in:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;SELECT SQL_VARIANT_PROPERTY(bar, 'BaseType') FROM dbo.tbFoo&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This will let you know whether your variable or column is actually being used as an int, varchar, nvarchar, etc.  There are other properties that can be checked as well using this &lt;a href="http://msdn.microsoft.com/en-us/library/ms178550.aspx"&gt;function&lt;/a&gt;; essentially anything that sp_help would usually give you.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Knowing the base type can be enormously helpful.  For example, when you encounter code that joins the table to itself to compare SQL_VARIANT values directly...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;SELECT * FROM dbo.tbFoo f1&lt;/div&gt;&lt;div&gt;INNER JOIN dbo.tbFoo f2&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;ON f1.bar = f2.bar&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;AND f1.ID &amp;lt; f2.ID&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now say you have dozens of processes inserting into this table, and they're not particularly standardized.  Say one of them inserts non-unicode strings (VARCHAR) while another inserts unicode strings (NVARCHAR).  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;INSERT INTO dbo.tbFoo SELECT CAST('A1B2C3' as varchar)&lt;/div&gt;&lt;div&gt;INSERT INTO dbo.tbFoo SELECT CAST('A1B2C3' as nvarchar)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you had CAST them in your query, they would be comparable, but without the cast, they &lt;b&gt;may or may not be&lt;/b&gt;, and you might not get the row back that you expected.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The best fix is to avoid writing this code, and be sure to CAST your SQL_VARIANTs into the type you're expecting to use, but if you need to restore functionality to this type of code, you can update your SQL_VARIANT column base type.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;UPDATE dbo.tbFoo SET bar = CAST(bar as NVARCHAR) WHERE SQL_VARIANT_PROPERTY(bar, 'BaseType') = 'varchar'&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All this may or may not help you with your SQL_VARIANT problems, as there's plenty of unexplored territory even within the issues I've touched upon here.  But it would have helped me yesterday.  Good luck.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-6314982227614532998?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/6314982227614532998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=6314982227614532998' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6314982227614532998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6314982227614532998'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/06/so-youve-got-problem-and-you-want-to.html' title='So you&apos;ve got a problem, and you want to solve it using SQL_VARIANT'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-178052411796168256</id><published>2011-05-11T14:27:00.000-07:00</published><updated>2011-05-13T13:32:33.207-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='tempdb'/><title type='text'>The Rare, Simple SQL Wait Fix</title><content type='html'>A "power user" reported some slowness on one of our big servers today while it was being pummeled by about 60 simultaneous executions of the same script.  The wait type was PAGELATCH_UP, which I vaguely recalled to mean something about allocation contention.  The Microsoft &lt;a href="http://download.microsoft.com/download/4/7/a/47a548b9-249e-484c-abd7-29f31282b04d/Performance_Tuning_Waits_Queues.doc"&gt;Waits and Queues tuning guide&lt;/a&gt; confirmed that, so I checked the wait resources.  They all started with 2:6 and 2:9, so it definitely had to do with tempdb.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This server is pretty beefy, a 4-socket quad-core with Xeon 7350s, but tempdb only had 8 files.  I know that the rule of thumb of 1 file per core is no longer quite so hard and fast, but I figured it probably wouldn't hurt here.  Created an extra 8 files, equalized the file sizes on the current ones, and had the user kick off the process again.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;No waits!  Or at least, no PAGELATCH_UP waits.  Some SOS_SCHEDULER_YIELDs and CXPACKETs, but I took that to mean that we had successfully shifted the bottleneck off of allocations and onto CPU, where it should be.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's rare that 5 minutes of configuration change can effect a significant gain in process speed, but it's pretty satisfying when it happens.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-178052411796168256?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/178052411796168256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=178052411796168256' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/178052411796168256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/178052411796168256'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/05/rare-simple-sql-wait-fix.html' title='The Rare, Simple SQL Wait Fix'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8262885202139518957</id><published>2011-04-01T06:54:00.000-07:00</published><updated>2011-04-01T06:59:26.765-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>In SSIS, memory corruption error == bad parameter passing</title><content type='html'>Had a strange situation with an SSIS package that would occasionally produce the following error message from an Execute SQL task:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After several rounds of machine reboots, file checking, and messing with the connection manager, I finally checked the actual query being executed (I know, way to work backwards).  It had a parameter being passed in that must have been hand-entered, because it was lacking the namespace, i.e. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ParamName1 &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;instead of &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;User::ParamName1.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Corrected that, and everything worked fine.  So the error message is thoroughly misleading, but if you investigate the query execution, you may find a bad parameter name.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8262885202139518957?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8262885202139518957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8262885202139518957' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8262885202139518957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8262885202139518957'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/04/in-ssis-memory-corruption-error-bad.html' title='In SSIS, memory corruption error == bad parameter passing'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-7489866530181555681</id><published>2011-03-16T14:48:00.001-07:00</published><updated>2011-03-16T14:54:23.534-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Resolver One'/><category scheme='http://www.blogger.com/atom/ns#' term='IronPython'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>More Resolver One nice-to-haves</title><content type='html'>Working on Resolver One stuff again, and came up with a few more things I'd like to see.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've been having problems moving some of my IronPython code out of my worksheet and into an IronPython module, but I assume that's due to my own lack of understanding of the clr - the external libraries seem to get hung up on the import statements and not get any further.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Which leads me to my first request: enable an easy way to reload a workbook.  At the moment, any time I make a change in an external file, I have to close the entire workbook and re-open it.  I can't just recalculate and have it re-import the module, I have to close the workbook (which generally means the entire program) and re-open it.  It would be nice to have a way to "Reload from disk" or something similar that does a thorough reinitialization of the environment.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The second thing is something I just posted about on the Resolver forums, so I'm hopeful that I'll come upon a solution via that line of inquiry, but basically, I want SSL support in Resolver.  I was trying to connect to a gmail server and use starttls() from smtplib, but couldn't do it because of the lack of SSL support in IronPython 2.6.0, which I believe is what's under the hood in Resolver One.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm using Resolver for a couple projects now, so here's hoping that development continues and that I can see some of these things working in the future.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-7489866530181555681?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/7489866530181555681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=7489866530181555681' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7489866530181555681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7489866530181555681'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/03/more-resolver-one-nice-to-haves.html' title='More Resolver One nice-to-haves'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-7312982994215131561</id><published>2011-03-11T13:01:00.000-08:00</published><updated>2011-03-11T13:55:08.067-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='remote working'/><title type='text'>Context switching is more expensive when bandwidth is limited</title><content type='html'>This post is just made up of more idle musings and could really be shortened to a tweet, but while on the road this week with access to the office via questionable and/or slow internet connections, I've noticed that context switching, both literal and figurative, is much more expensive with low bandwidth.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This applies across all sorts of situations.  I get a lot of IMs from co-workers, for example.  Normally I don't notice their impact much, since I have two big monitors worth of screen real estate and I can switch back and forth between IM windows and coding or testing quickly.  But with less screen space (1280 x 800 instead of 3840 x 1080), the IM windows take up more space and I have to move them around frequently, which takes up more time.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also, with slow internet connections, actually switching between windows is sometimes difficult, as redrawing a bigger chunk of the screen causes the whole connection to freeze for as long as several minutes at a time.  And as upstream bandwidth is always more limited than downstream, sometimes my typing or clicks don't get transmitted for extended periods of time.  It's very frustrating, to the point where I'm planning to get a mobile internet solution of some kind very soon.  The travel has also cost me quite a few mobile phone minutes, as I can't use VOIP over the sketchy internet connections.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In other remote working news, I've noticed two startups in the space mentioned recently on TechCrunch: &lt;a href="http://l.aunch.it/xoWT"&gt;LiquidSpace&lt;/a&gt; and &lt;a href="http://loosecubes.com"&gt;LooseCubes&lt;/a&gt;.  I'm hoping that one or both will help provide the co-working experience I've been seeking and not finding in DC (and potentially elsewhere).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-7312982994215131561?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/7312982994215131561/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=7312982994215131561' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7312982994215131561'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7312982994215131561'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/03/context-switching-is-more-expensive.html' title='Context switching is more expensive when bandwidth is limited'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-6660163481308770200</id><published>2011-01-27T08:42:00.000-08:00</published><updated>2011-01-27T08:55:33.316-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='starbucks'/><category scheme='http://www.blogger.com/atom/ns#' term='remote working'/><category scheme='http://www.blogger.com/atom/ns#' term='co-working'/><title type='text'>The Perils of Laptopistan</title><content type='html'>I'm out in Laptopistan again today, this time in the principality of Starbucks, but not by choice.  My power is out for the 3rd or 4th time since moving to the DC burbs, and in order to get any work done I had to get somewhere with Wifi.  This Starbucks is packed, of course, with other people whose power is also out, making the internet access slow as molasses, and seating and power very difficult to come by.  Fortunately, I brought a mini power strip, so I could add my laptop and Krystal's phone to an outlet without displacing anyone.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, my complaint is not so much that the situation is impossible, it's just small extra costs to this type of remote working:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;- 20 mins looking for street parking in the snow = lost work time&lt;/div&gt;&lt;div&gt;- slow internet = lower productivity&lt;/div&gt;&lt;div&gt;- large latte = 4x the unit cost of coffee at home (which is better anyway, thanks to our Baratza grinder and French press)&lt;/div&gt;&lt;div&gt;- 20 mins spent waiting for a table = lost work time&lt;/div&gt;&lt;div&gt;- no power outlets available = additional capital goods required (power strip) plus the need to remember to bring them&lt;/div&gt;&lt;div&gt;- limited-time parking meters requiring movement of car after 4 hours = lost work time&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If anyone at my office is reading this, don't worry, I'll make up the lost time, but my complaint still stands, because that cuts into my free time.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, obviously some establishments are better-suited to remote working than others; Peregrine Espresso is paradise compared to Starbucks, but it would have taken 90+ mins to get there this morning through the snow and non-working traffic lights.  All of these complaints could be remedied by having access to a proper co-working space, so I suppose the best approach is to quantify these costs, find the appropriate break-even point, and seek co-working space at or below that price point.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-6660163481308770200?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/6660163481308770200/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=6660163481308770200' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6660163481308770200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6660163481308770200'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/01/perils-of-laptopistan.html' title='The Perils of Laptopistan'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-4211014553596501987</id><published>2011-01-05T08:45:00.000-08:00</published><updated>2011-01-05T08:50:45.705-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data'/><category scheme='http://www.blogger.com/atom/ns#' term='finance'/><category scheme='http://www.blogger.com/atom/ns#' term='wtf'/><title type='text'>Daily WTF: Financial Data Provider edition</title><content type='html'>A data provider that shall remain nameless (at least while I'm still employed at my current office) sends us daily CSV files.  I was looking into a failure of the load of one of these files and noticed this... (values modified to protect the sanctity of the data)&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[header row]&lt;/div&gt;&lt;div&gt;[first data row]&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;DAM, 0.2309674, 0.2309676,&lt;/div&gt;&lt;div&gt;&lt;div&gt;POC, 0.000301957, 0.000301963,&lt;/div&gt;&lt;div&gt;* The [big data provider] Closing Spot Rates provided by [big data provider a] plc in conjunction with [big data provider b].The [big data provider] plc shall not be liable for any errors in or delays in providing or making available the data contained within this service or for any actions taken in reliance on the same except to the extent that the same is directly caused by its or its employees' negligence.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks, [big data provider]!  But next time, maybe you could shove that disclaimer someplace other than a file produced and consumed exclusively by machines, which happen to appreciate a specific format for their files, especially when said files are called, explicitly, Comma-Separated Values?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-4211014553596501987?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/4211014553596501987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=4211014553596501987' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4211014553596501987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4211014553596501987'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2011/01/daily-wtf-financial-data-provider.html' title='Daily WTF: Financial Data Provider edition'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2140771573358165566</id><published>2010-12-17T10:31:00.000-08:00</published><updated>2010-12-17T11:25:04.916-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='remote working'/><title type='text'>Back in Laptopistan</title><content type='html'>At Port City Java in Capitol Hill today, just up the street from Peregrine, where I was &lt;a href="http://nyc-dba.blogspot.com/2010/12/notes-from-laptopistan.html"&gt;last week&lt;/a&gt;, and there's a fair concentration of laptop users, but certainly not the packed house that there was at Peregrine.  I'm guessing that's correlated to Port City's 3 stars on Yelp vs Peregrine's 4.  But the WiFi is fast and there are some comfy chairs.  Judgement on coffee still forthcoming.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One of the difficulties of working remotely in a shared environment is phone calls.  I had a meeting today which is often cancelled, so I was hoping that it would be again today.  But it wasn't, so I had to fire up Skype (which, thankfully, worked fine here), dial up the conference line, and participate in the call, wincing every time I had to speak from fear of offending the people around me.  Fortunately, there was only one other person besides my girlfriend sitting nearby, so I wasn't as concerned as I would have been, but in a tighter space like Peregrine, it would be impossible to take a phone call without bothering people.  The alternative would be to go outside or sit in one's car, both of which I've done in the past, but it's below freezing outside and my car is more than a block away, making neither of those options particularly palatable.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I suppose that in a true co-working space, phone calls would be expected and unavoidable, so both my concern and others' irritation would be lower.  But I have yet to identify a suitable co-working facility in DC, and it's nice to get to change scenery each time I go to a new cafe, so for now I'll just live with the minor difficulties and keep hunting for the best WiFi and coffee. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2140771573358165566?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2140771573358165566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2140771573358165566' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2140771573358165566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2140771573358165566'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2010/12/back-in-laptopistan.html' title='Back in Laptopistan'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1395427844817600601</id><published>2010-12-16T13:10:00.000-08:00</published><updated>2010-12-16T14:48:42.410-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Resolver One'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>More notes on Resolver One</title><content type='html'>Still generally liking Resolver One, but there are some limitations that are bothering me and associated requests I'd like to make.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1) &lt;b&gt;Sorting!&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;How is there no sorting in place yet?  They implemented CHITEST before sorting-in-place!?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;2) &lt;b&gt;Assignment&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Some more "magic" assignment methods would be welcome.  Something like &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;myCellRange = myListOfLists # aka 2D array&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;or&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;myRow = myList&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That seems like a straightforward thing to implement, but instead I have to iterate over both and assign each value manually.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;3) &lt;b&gt;Row and Column Numbers&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;It would be very helpful if the code editor had a display with row and column numbers at the bottom.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1395427844817600601?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1395427844817600601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1395427844817600601' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1395427844817600601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1395427844817600601'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2010/12/more-notes-on-resolver-one.html' title='More notes on Resolver One'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5056718527512514898</id><published>2010-12-10T14:27:00.000-08:00</published><updated>2010-12-17T11:25:30.244-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='remote working'/><title type='text'>Notes from Laptopistan</title><content type='html'>Credit to David Sax of the &lt;a href="http://www.nytimes.com/2010/12/05/nyregion/05laptop.html"&gt;NYT&lt;/a&gt; for the name.  Trying the working mode advocated in the article and occupying a spot in a cafe once a week or so.  Clearly it requires some technique, however...&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This afternoon, I worked out of &lt;a href="http://peregrineespresso.com/"&gt;Peregrine Espresso&lt;/a&gt; in Capitol Hill.  It's a nice place, with good tea and coffee, so I guess I shouldn't have been surprised that it would be full of laptoppers.  Every seat was full when I walked in.  Fortunately, one person was packing up, so I got the table he vacated, but then gave it up to some people who were trying to have a conversation in favor of a seat at a bar.  But after about an hour my back ached, and I didn't like fighting for elbow space with the people on either side.  Plus, it's distracting to have two bright laptop screens on either side of you - I kept glancing over at each without meaning to, and alternated between feeling superior and jealous when noting that they were not doing any actual work.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Additional gear for the cafe survival kit for next time: headphones and an extension cord.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5056718527512514898?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5056718527512514898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5056718527512514898' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5056718527512514898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5056718527512514898'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2010/12/notes-from-laptopistan.html' title='Notes from Laptopistan'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2742803799224666626</id><published>2010-12-02T13:55:00.001-08:00</published><updated>2010-12-02T14:06:30.028-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Resolver One'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Resolver One CellRange oddities</title><content type='html'>I've started working on a project in which we're using Resolver One as a dashboard.  The workbook consumes multiple data sources (services, DB, YAML files, etc.), collates and formats, and may eventually do other cool stuff like kick off simulations or generate charts.  But we're still in the early stages, so I'm just fleshing out the configuration routines and table displays.&lt;div&gt;&lt;br /&gt;What I've found so far is that Resolver One is a cool package, but seems to have some weak points.  The documentation is okay, but the layout seems less than intuitive, and the volume of documentation is somewhat lacking in comparison to The Enterprise Spreadsheet app.  That's to be expected, so it doesn't bother me much.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The thing that does bother me is an apparent code deficiency in combination with my inability to log into their support forums to ask questions.  I assume the forum issue is temporary and will be resolved (ha) shortly, but the code issue seems like a bug.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Basically, my problem is that CellRanges don't act Pythonically, or even correctly, it would seem.  For one, you can't do this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;cellrange.HeaderRow = worksheet.HeaderRow&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why not?  That seems like the most logical (and Pythonic) operation you could perform.  I actually couldn't set the HeaderRow through any means, no matter what sort of value I passed in.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had a second issue, but I just determined that it was user error and fixed it.  Will continue this post if I come across something else...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2742803799224666626?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2742803799224666626/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2742803799224666626' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2742803799224666626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2742803799224666626'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2010/12/resolver-one-cellrange-oddities.html' title='Resolver One CellRange oddities'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-7144500982426902687</id><published>2010-10-18T12:22:00.000-07:00</published><updated>2010-10-18T13:00:30.525-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2008'/><title type='text'>Connection Manager Attributes Changed error in SSIS can be resolved by cleaning up your query</title><content type='html'>Just resolved a funny issue that was making me crazy for about 15 minutes.  In the "Use results of an SQL query" window in the SQL Query a Lookup task in SSIS 2005, I pasted in a query I had written in SQL Management Studio 2008 R2.  The formatting looked a little funny, with the little squares in place of some line breaks and tabs all over the place, but I ignored it and clicked through to the Columns tab.  At the bottom of the tab, where errors and warnings appear, I got this:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Connection Manager attributes have changed.  The mappings of previous columns are no longer valid.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The message stayed there even after I changed the OLE DB connection manager, added and removed columns to the lookup, and clicked every available button in the Lookup Transformation Editor.  And it prevented me from clicking OK to finalize and save the transformation.  I decided that I should look through the code for any bad syntax or other anomalies, but it was difficult with the screwy formatting, so I "washed" it by cutting and pasting it into Notepad++ and then back into SSIS. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And guess what?  Not only did the code look better, the warning message went away.  So if you're seeing that warning, try cleaning up the formatting of your SQL query.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-7144500982426902687?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/7144500982426902687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=7144500982426902687' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7144500982426902687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7144500982426902687'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2010/10/connection-manager-attributes-changed.html' title='Connection Manager Attributes Changed error in SSIS can be resolved by cleaning up your query'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2554915745349852402</id><published>2010-10-12T07:00:00.000-07:00</published><updated>2010-10-12T07:02:08.278-07:00</updated><title type='text'>Python scratchpad entry</title><content type='html'>Simplest syntax I've found for converting dates to datetimes, given a date d:&lt;div&gt;&lt;br /&gt;&lt;div&gt;datetime.combine(d, time())&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've got a couple other blog entries in the pipeline, but I've had blog apathy lately and haven't finished any of them.  Hopefully soon.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2554915745349852402?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2554915745349852402/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2554915745349852402' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2554915745349852402'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2554915745349852402'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2010/10/python-scratchpad-entry.html' title='Python scratchpad entry'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-3099052939950067188</id><published>2010-03-10T07:21:00.000-08:00</published><updated>2010-03-10T07:47:15.496-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='indexing'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>FILLFACTOR is really not that complicated</title><content type='html'>I keep coming across code that explicitly sets the FILLFACTOR option on an index for no good reason.  FILLFACTOR is not complicated - it leaves some percentage of index pages empty in order to prevent page splits and resulting fragmentation and low page density during inserts into the middle of a key range.  It can be a useful option iff:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;- the table will actually get rows inserted into it!&lt;/div&gt;&lt;div&gt;- there is no monotonically increasing index key (like a primary key identity column)&lt;/div&gt;&lt;div&gt;- the author is intimately familiar with the usage pattern of the table and knows how to balance the additional I/O required to read the extra pages with the I/O saved by preventing page splits&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Otherwise you're just taking an automatic IO performance hit of n% (where n is 100-(FILLFACTOR)) for no good reason.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Particularly ridiculous is the code that I've found which does something like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;CREATE TABLE #tempstuff (foo int, bar varchar(20))&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;INSERT INTO #tempstuff SELECT foo, bar FROM dbo.sometable&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;CREATE INDEX ix_reallyNotUseful ON #tempstuff (foo, bar) WITH FILLFACTOR = 90&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First off, make the index clustered.  If this table will not see any more inserts, there's no reason to leave it as a heap and then have to create surrogate keys in order to build the non-clustered index.  Might as well physically order it by the index keys and gain the additional performance of the clustered index.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Second, the table is not getting any more inserts after this.  Why would you care about leaving extra space on the pages?  Set the FILLFACTOR to 100!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This has been a public service rant from your irritable neighbor database engineer.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-3099052939950067188?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/3099052939950067188/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=3099052939950067188' title='35 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/3099052939950067188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/3099052939950067188'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2010/03/fillfactor-is-really-not-that.html' title='FILLFACTOR is really not that complicated'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>35</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8067422984877198275</id><published>2010-01-19T10:52:00.000-08:00</published><updated>2010-01-19T12:20:44.643-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CTEs'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><title type='text'>Nested CTEs</title><content type='html'>Had my first need for nested CTEs today - for a table with prices by object and another with adjustment factors by object, I needed to multiply the prices by all factors occurring after the price date.  This could be done in the C++ code I was working on via an ugly &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;for&lt;/span&gt; loop for each price date, but I knew there had to be a better, set-based way within SQL.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The answer was nested Common Table Expressions (CTEs), which Microsoft officially says are not supported, but which can actually be implemented by defining multiple CTEs (with a comma between each) and using the first one in the second.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For this application, the first CTE orders the object ids and adjustment factors and adds row numbers.  An ORDER BY would have sufficed to order everything, but in order to avoid inefficient subqueries in the next CTE, I needed consistent row numbering.  The second CTE aggregates the adjustment factors for each date by recursing down the ordered factors for each object and multiplying them as it goes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This solution condenses all the selection logic into one set of SQL statements, is compact, fairly readable, and has a better complexity profile than the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;for &lt;/span&gt;loop alternative.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(Table and column names changed to protect confidentiality.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;WITH AdjFactorsOrdered (ObjectId, AdjDate, AdjFactor, ord) AS&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;(SELECT ObjectId, AdjDate, AdjFactor, ROW_NUMBER() OVER (PARTITION BY ObjectId ORDER BY AdjDate desc)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;FROM vwAdjFactors&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;WHERE AdjDate &gt; '2009-01-01'&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;AND AdjDate &lt;= '2010-01-01'&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;AND ISNULL(AdjFactor, 1) != 1&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;AND SubTypeId != 1&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;),&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;AdjFactorsCombined (ObjectId, AdjDate, AdjFactor, ord) AS&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;(SELECT ObjectId, AdjDate, AdjFactor, ord&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;FROM AdjFactorsOrdered&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;WHERE ord = 1&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;UNION ALL&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;SELECT mul.ObjectId, mul.AdjDate, base.AdjFactor * mul.AdjFactor as AdjFactor, mul.ord&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;FROM AdjFactorsCombined base&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;INNER JOIN AdjFactorsOrdered mul&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ON mul.ord = base.ord + 1&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;AND mul.ObjectId = base.ObjectId&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;)&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;SELECT ObjectId, AdjDate, AdjFactor &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;FROM AdjFactorsCombined &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ORDER BY ObjectId, AdjDate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8067422984877198275?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8067422984877198275/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8067422984877198275' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8067422984877198275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8067422984877198275'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2010/01/nested-ctes.html' title='Nested CTEs'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2565934204516682303</id><published>2010-01-14T12:11:00.000-08:00</published><updated>2010-01-14T12:22:58.268-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='scripting'/><title type='text'>Daily WTF: SSIS edition</title><content type='html'>With apologies to Alex P of the real &lt;a href="http://thedailywtf.com/"&gt;Daily WTF&lt;/a&gt;, here's my latest legacy code annoyance:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We have a variety of data imports that employ multiple SSIS packages in order to break the import logic into manageable, consistent stages.  So far, so good.  Except that a few particularly intrepid former team members of mine preferred to construct parent packages that called child packages, complete with variable passing to maintain state awareness, directory location consistency, dynamic environment configuration, etc. instead of just calling them from the job management system in successive tasks.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Oh, and none of these packages are in source control, they're just scattered about the file system like leaves in an ill-kept yard.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All of this leads me to my current exercise in SSIS surgery - I needed to change the behavior of one of these packages, so I decided to update it to our modern standards of SSIS behavior and move it to a new location.  This one has a final step that calls the next package, a process I wasn't quite prepared to rework, so I wanted to simply update the directory in which it expects to find the next package. "Hopefully it does it on the fly," I thought, "since all the related packages are kept in the same directory and it could just pull the working directory at runtime..."  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;No such luck.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Instead, the package uses a variable to hold the path of the next package, which is configured via an expression that pulls from another variable, which pulls from another variable, which pulls from a package configuration, which pulls from a registry string.  Which I don't have on my machine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Got that?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Registry Key -&gt; Package Configuration -&gt; Variable A -&gt; Variable B -&gt; Variable C -&gt; Script Task&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've got news for you, former developer: it's called &lt;b&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.io.directory.getcurrentdirectory.aspx"&gt;IO.Directory.GetCurrentDirectory()&lt;/a&gt;&lt;/b&gt;.  &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2565934204516682303?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2565934204516682303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2565934204516682303' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2565934204516682303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2565934204516682303'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2010/01/daily-wtf-ssis-edition.html' title='Daily WTF: SSIS edition'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1161132094079254031</id><published>2009-12-29T10:39:00.001-08:00</published><updated>2009-12-29T11:45:40.737-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='audio'/><category scheme='http://www.blogger.com/atom/ns#' term='headphones'/><title type='text'>Off Topic: In-Ear Monitors (aka earbuds)</title><content type='html'>Just received my latest pair of serious headphones, a set of Ultimate Ears Triple.Fi 10vis, and couldn't resist posting some thoughts.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some background: as it says in my profile, I used to work in the live and recorded sound biz, and I'm moderately obsessed with good sound.  My go-to headphones are still my Sony MDR-7506s, but the full list has included...&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;AKG K240&lt;/li&gt;&lt;li&gt;Etymotic ER6i&lt;/li&gt;&lt;li&gt;Etymotic ER-4P&lt;/li&gt;&lt;li&gt;Sennheiser CX300&lt;/li&gt;&lt;li&gt;Sennheiser CX400&lt;/li&gt;&lt;li&gt;Sennheiser HD650&lt;/li&gt;&lt;li&gt;Sennheiser HD280&lt;/li&gt;&lt;li&gt;Sony MDR-7506&lt;/li&gt;&lt;li&gt;Sony MDR-V600&lt;/li&gt;&lt;li&gt;Sony MDR-V700&lt;/li&gt;&lt;li&gt;UE Triple.Fi 10vi&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;along with plenty of cheaper junk for travel, gym, etc.  I use the AKGs with a Behringer UCA202 at work, the Sony MDR-7506s when listening at home or DJing, and I have been happily using the Etymotic ER4s with my iPhone 3GS, but when the UEs came up in Amazon's Gold Box for $99, I couldn't resist and picked up a pair.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've been A/Bing the UEs and Etymotics for the last hour, and I have to say, despite the usual price difference (the UEs usually retail for about 2x as much), the comparison is not cut and dried.  My first impressions are as follows, with the "winner" in each area in bold in case you don't want to read the whole thing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;Lows&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;The biggest known weakness of the Etymotics is the bass response, even when the flanges are shoved all the way down your ear canal and are tickling your temporal lobe, and the &lt;b&gt;UEs&lt;/b&gt; are the clear winner here.  The thump and throb of the bass on NIN's Gave Up and Zero Sum was much tighter, clearer, and more extended on the UEs, while the Etymotics gave up on clarity as the frequencies descended toward 20 Hz.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;Highs&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;On the other end of the spectrum, the &lt;b&gt;Etymotics&lt;/b&gt; redeemed themselves.  The opening chords of Band of Horses' The Funeral gave me goosebumps, and the NIN tracks generally had more sizzle on the cymbals and more edge to the guitars and synths.  The UEs sound a bit darker, despite the better frequency separation lent by the multiple drivers.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Clarity&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Still, the effectiveness of the &lt;b&gt;UEs&lt;/b&gt;' multiple drivers can be heard in the clarity of the sound.  Despite the compression of the some of the MP3s I have on my iPhone, the UEs carved out more of a pocket for each instrument and frequency range.  I'm sure this difference between the headphones would be more pronounced with higher-quality amplification, but I could hear, for example, the muddying effect of heavy bass on the mids in the Etymotics, but not in the UEs.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Soundstage&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Somehow, even put up against the multiple drivers, the &lt;b&gt;Etymotics &lt;/b&gt;produced a wider, more defined soundstage.  Special effects like dynamic panning were more pronounced, and subtle placement of instruments within the field was clearer, especially on quieter tracks with more headroom/less compression.  The better high frequency response on the Etymotics may have something to do with this perception.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Other&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Because I use these headphones in the real world - on airplanes, buses, NYC subways, etc., there are some ancillary considerations that have a real effect on my headphone preference.  Despite the fact that the UEs are billed as noise-isolating, the &lt;b&gt;Etymotics &lt;/b&gt;were clearly superior at blocking outside noise, even in the relatively quiet environment of my office.  The cord is a bit longer and heavier on the &lt;b&gt;Etymotics&lt;/b&gt;, but lacks the built-in microphone of the &lt;b&gt;UEs&lt;/b&gt;. The earbud flanges on the Etymotics take quite a bit of getting used to, whereas the &lt;b&gt;UEs&lt;/b&gt;, while they don't fit as snugly, come with 4 different sets of tips and are immediately comfortable and feel easier to wear for long periods.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;However, with the sound quality a near wash between the two, the main reason I'm switching from the Etymotics to the &lt;b&gt;Ultimate Ears&lt;/b&gt; is the filters.  The Etymotics have dirt/debris filters that fit inside the driver enclosure behind the flanged tips and must be changed every time they get clogged.  They are tiny, difficult to replace, and not tremendously cheap - $15 gets you 3 sets of filters, and I have to change mine every few months at most.  I consider the filter system to be the Achilles heel of the otherwise-excellent Etymotics, and I'm hoping for substantially less maintenance with the UEs.  We'll see how it goes.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1161132094079254031?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1161132094079254031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1161132094079254031' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1161132094079254031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1161132094079254031'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2009/12/off-topic-in-ear-monitors-aka-earbuds.html' title='Off Topic: In-Ear Monitors (aka earbuds)'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1966493680275180298</id><published>2009-10-21T13:58:00.000-07:00</published><updated>2009-10-21T14:10:47.371-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='notification services'/><title type='text'>Notification Services doesn't like version mismatches</title><content type='html'>I was pinged today to check out a failed installation of Notification Services with a vendor app.  The vendor consultant was telling us that there was a mismatch in the version of SQL Tools installed, which sounded odd to me, since generally the tools are consistent between versions and the engines are different.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I tried to start up the Notification Services instance and got a 1359 error:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;---------------------------&lt;/div&gt;&lt;div&gt;Services&lt;/div&gt;&lt;div&gt;---------------------------&lt;/div&gt;&lt;div&gt;Could not start the NSxxxx service on Local Computer.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Error 1359: An internal error occurred.&lt;/div&gt;&lt;div&gt;---------------------------&lt;/div&gt;&lt;div&gt;OK   &lt;/div&gt;&lt;div&gt;---------------------------&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Inspecting the error log, I found this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Description:&lt;/div&gt;&lt;div&gt;The Notification Services instance encountered an error in one of its components and must stop.&lt;/div&gt;&lt;div&gt;EventParameters:&lt;/div&gt;&lt;div&gt;  Instance Name: xxxxx&lt;/div&gt;&lt;div&gt;  Problem Description: The database was created with or upgraded to a different edition of Notification Services. Use the Notification Services edition that the database expects.&lt;/div&gt;&lt;div&gt;Notification Services Edition: Standard Edition&lt;/div&gt;&lt;div&gt;Database Edition: Enterprise Edition&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So it turns out that the consultant was partially correct - Notification Services won't start if the version is mismatched between the engine installation and its corresponding SQL Server instance.  Good to know.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1966493680275180298?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1966493680275180298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1966493680275180298' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1966493680275180298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1966493680275180298'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2009/10/notification-services-doesnt-like.html' title='Notification Services doesn&apos;t like version mismatches'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-4835274867994254443</id><published>2009-09-17T08:08:00.000-07:00</published><updated>2009-10-16T13:36:17.903-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='whitespace'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='regular expressions'/><title type='text'>Regex to remove end-of-line white space</title><content type='html'>Utilizing the blog as my public scratchpad (as usual), here's a regex for removing whitespace from the end of all lines.  Useful when pulling up the text of a SQL object with sp_helptext and then creating it again.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Replace: [ \t]+\n&lt;/div&gt;&lt;div&gt;With: \n&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-4835274867994254443?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/4835274867994254443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=4835274867994254443' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4835274867994254443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4835274867994254443'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2009/09/regex-to-remove-end-of-line-white-space.html' title='Regex to remove end-of-line white space'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-6181514002137221327</id><published>2009-06-03T13:09:00.000-07:00</published><updated>2009-06-03T13:48:12.525-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='IO'/><category scheme='http://www.blogger.com/atom/ns#' term='bulk insert'/><title type='text'>Conflicting BULK INSERTs</title><content type='html'>Let me start by saying that this is not a post about &lt;a href="http://msdn.microsoft.com/en-us/library/dd425070.aspx"&gt;concurrent BULK INSERTs into a single table&lt;/a&gt; or &lt;a href="http://sqlcat.com/technicalnotes/archive/2009/04/06/bulk-loading-data-into-a-table-with-concurrent-queries.aspx"&gt;SELECTs during a BULK INSERT&lt;/a&gt;, both of which the SQL CAT has covered pretty effectively, along with many other questions about bulk data loading.  My problem is with concurrent BULK INSERTs into different tables on the same database.&lt;br /&gt;&lt;br /&gt;Basically, there are two different data sets, one large and one small, that get BULK INSERTed into two different tables in the same DB on different schedules.  Like Alan's bicycle in &lt;a href="http://books.google.com/books?id=PB4S6015DP0C&amp;amp;dq=cryptonomicon&amp;amp;printsec=frontcover&amp;amp;source=bn&amp;amp;hl=en&amp;amp;ei=wtomSp2IBpCq8gT2g9CBDw&amp;amp;sa=X&amp;amp;oi=book_result&amp;amp;ct=result&amp;amp;resnum=4#PPA2,M1"&gt;Cryptonomicon&lt;/a&gt;, every so often the two schedules will align and the chain will fall off, or more accurately, the big BULK INSERT will hold up the small BULK INSERT.  There doesn't seem to be a reason for the SQL engine to block one with the other; they're not hitting the same table, so locking should not be a problem, and the machine in question is a dual quad-core, so SOS_SCHEDULER_YIELDs are not prevalent. &lt;br /&gt;&lt;br /&gt;OK, if it's not the SQL engine, it's probably a shared resource issue.  Sure enough, an inspection of the wait types during a concurrent execution of these inserts revealed a lot of PAGEIOLATCH_SH, indicating a disk problem.  But this database is in Simple recovery mode, so it shouldn't be doing a lot of logging on a bulk-logged operation like BULK INSERT.  We should just be writing dirty pages to memory and then checkpointing at our leisure, right?  Why are the disks getting hit so hard?  Unless we don't have enough memory to write those dirty pages...&lt;br /&gt;&lt;br /&gt;Which a perfmon counter log revealed to be precisely the case.  The box only has 3.5 GB of RAM, has a number of other applications running, and shows high levels of paging and low Page Life Expectancy.  The lack of memory available to SQL means that the larger dataset being BULK INSERTed won't fit into RAM, so checkpointing starts almost immediately and blocks the smaller BULK INSERT from completing until the slow local disks can finish with the bigger one.  The easiest and cheapest solution will almost certainly be to add RAM, if only I can talk Systems Engineering into digging some up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-6181514002137221327?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/6181514002137221327/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=6181514002137221327' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6181514002137221327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6181514002137221327'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2009/06/conflicting-bulk-inserts.html' title='Conflicting BULK INSERTs'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8846023816036674701</id><published>2009-04-22T15:11:00.000-07:00</published><updated>2009-04-23T07:07:46.536-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>Performance of LIKE vs = in SQL queries</title><content type='html'>Got a question from a coworker yesterday about the relative performance of LIKE vs = in a SQL query, and had to think about it a bit.  He wanted to know whether there was a performance penalty to using LIKE if there were no wildcards.  In other words, if this:&lt;br /&gt;&lt;br /&gt;SELECT * FROM tbFoo WHERE colA LIKE 'bar'&lt;br /&gt;&lt;br /&gt;would perform equivalently to this:&lt;br /&gt;&lt;br /&gt;SELECT * FROM tbFoo WHERE colA = 'bar'&lt;br /&gt;&lt;br /&gt;My knee-jerk response was that the = would be faster, but I thought about it and realized that the query optimizer would actually see them as the same thing.  A check of the query plans against a quickly-created tbFoo confirmed it.  So that's what I told him.&lt;br /&gt;&lt;br /&gt;Except that I realized a moment later that there was a major caveat - the query optimization depends on how the statement is parameterized.  If it's purely ad hoc SQL and being compiled at run-time, then the statements are equivalent, but if there's going to be any plan re-use, either by including the statement in a stored proc or preparing it and executing via sp_executesql, the LIKE will impose a significant penalty.&lt;br /&gt;&lt;br /&gt;This is because the optimizer doesn't know at compile time whether the parameter to the LIKE operator will contain a wild card, so it can't use the more specific optimization (including index selection) that it could with an = operator.  So if you mostly pass parameters without wildcards, you will be executing a suboptimal query plan.  Keep this in mind when designing your query!&lt;br /&gt;&lt;br /&gt;---&lt;br /&gt;&lt;br /&gt;I realized after writing this that this topic has been covered in more depth and with more eloquence by &lt;a href="http://www.sommarskog.se/dyn-search-2005.html"&gt;Erland Sommarskog&lt;/a&gt; and any number of other SQL MVPs and bloggers, but this post is already written, so I'm releasing it into the wild anyway.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8846023816036674701?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8846023816036674701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8846023816036674701' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8846023816036674701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8846023816036674701'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2009/04/performance-of-like-vs-in-sql-queries.html' title='Performance of LIKE vs = in SQL queries'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5052252890061554484</id><published>2009-04-22T14:53:00.000-07:00</published><updated>2009-04-22T15:11:19.678-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Notepad++'/><title type='text'>Notepad++ 5.3.1 breaks the Compare plugin</title><content type='html'>I use Notepad++ all the time for quick editing of SQL, Python, XML, and all sorts of other types of files, and when I opened it today, it told me there was an update available, so I updated to 5.3.1 .&lt;br /&gt;&lt;br /&gt;Then this afternoon when I went to compare two SQL files using the Compare plugin, I couldn't find it, and spent a good 5 minutes combing through the menus before I realized it was really gone.  Arggh!&lt;br /&gt;&lt;br /&gt;I use the Compare tool all the time, so I immediately downgraded to version 5.2, where it still works.  So just a note of caution if you use Compare in Notepad++, 5.3.1 appears to break it - hopefully they'll get that straightened out soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5052252890061554484?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5052252890061554484/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5052252890061554484' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5052252890061554484'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5052252890061554484'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2009/04/notepad-531-breaks-compare-plugin.html' title='Notepad++ 5.3.1 breaks the Compare plugin'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-383598915935175750</id><published>2009-03-13T07:14:00.000-07:00</published><updated>2009-03-16T11:03:31.003-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyodbc'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>pyodbc doesn't seem to like BLOBs</title><content type='html'>I tried to pull a Binary Large OBject out of a SQL Server database yesterday via pyodbc, and it blew up.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;In [4]: c = pyodbc.connect('DRIVER={SQL Server};SERVER=&lt;/span&gt;&lt;span style="font-style: italic;font-family:courier new;" &gt;servername&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;In [5]: r = c.execute('select Blob from dbo.tbDoc where DocID = 8')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;In [6]: row = r.fetchone()&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);font-family:courier new;" &gt;assertion failed: getdata.cpp(171)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);font-family:courier new;" &gt;cbRead == 0 || pch[cbRead-element_size] != 0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And crashed my IPython shell, to boot.&lt;br /&gt;&lt;br /&gt;Python's DB API spec (aka &lt;a href="http://www.python.org/dev/peps/pep-0249/"&gt;PEP 249&lt;/a&gt;) doesn't appear to specify exactly how to handle BLOBs, but it does mention them, so I presume they're supposed to be supported.  I wound up grabbing this particular BLOB in a C# app instead, but this seems like it could be an issue in the future, so if anyone knows what's going on, please let me know.  Otherwise I'll dig into this issue next time I have some spare time or a pressing need to manipulate BLOBs in Python.&lt;br /&gt;&lt;br /&gt;UPDATE: I wasn't on the latest build of pyodbc, so I updated to 2.1.3.  After updating, I was able to fetch the binary stream from that row.  Hooray! &lt;br /&gt;&lt;br /&gt;Although when attempting to print it out, I got some weird behavior - my PC's internal speaker started beeping like mad and the window stopped responding.  As my colleague said:&lt;br /&gt;&lt;br /&gt;P.V. [1:57 PM]:&lt;br /&gt;What the hell was stored in that blob?&lt;br /&gt;Ira Pfeifer [1:58 PM]:&lt;br /&gt;just a hex stream&lt;br /&gt;P.V. [1:58 PM]:&lt;br /&gt;This is like something from Gibson.&lt;br /&gt;&lt;br /&gt;Strange...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-383598915935175750?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/383598915935175750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=383598915935175750' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/383598915935175750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/383598915935175750'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2009/03/pyodbc-doesnt-seem-to-like-blobs.html' title='pyodbc doesn&apos;t seem to like BLOBs'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-3746400979375874981</id><published>2009-02-02T11:47:00.000-08:00</published><updated>2009-02-02T11:54:36.070-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Job Scheduler'/><category scheme='http://www.blogger.com/atom/ns#' term='OSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='SQLCMD'/><title type='text'>Weird SQLCMD issue</title><content type='html'>I've got a server that runs the open source &lt;a href="http://sourceforge.net/projects/jobscheduler/"&gt;Job Scheduler&lt;/a&gt; to execute scheduled tasks, and I encountered a strange problem with SQLCMD today.  Basically, a very simple script fails to execute:&lt;br /&gt;&lt;br /&gt;2009-02-02 13:52:01.224 [info]   C:\Program Files\scheduler&gt;sqlcmd -S TestServer1 -E -i "c:\temp\test.sql"&lt;br /&gt;2009-02-02 13:52:01.224 [info]   SCHEDULER-915  Process event&lt;br /&gt;2009-02-02 13:52:01.224 [ERROR]  SCHEDULER-280  Process terminated with exit code 1 (0x1)&lt;br /&gt;&lt;br /&gt;This script executes without a problem on the command line, and&lt;br /&gt;&lt;br /&gt;echo %errorlevel%&lt;br /&gt;&lt;br /&gt;after its execution returns 0.  I thought this might be an authentication issue, but switching to SQL authentication and entering the credentials explicitly on the command line produced the same result.&lt;br /&gt;&lt;br /&gt;The strangest part of the whole thing is that switching from &lt;span style="font-weight: bold;"&gt;SQLCMD&lt;/span&gt; to &lt;span style="font-weight: bold;"&gt;OSQL&lt;/span&gt; makes the script work fine.  I'd rather use SQLCMD, but I don't have time to investigate the minute difference in output that's causing JS to barf on it, so I guess it's back to the old reliable OSQL.  At least until it's no longer supported.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-3746400979375874981?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/3746400979375874981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=3746400979375874981' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/3746400979375874981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/3746400979375874981'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2009/02/weird-sqlcmd-issue.html' title='Weird SQLCMD issue'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-6301402893773719223</id><published>2009-01-22T11:49:00.000-08:00</published><updated>2009-01-22T12:24:29.181-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='transactions'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='msdtc'/><title type='text'>SSIS transactions, or Another Reason To Hate Windows Firewall</title><content type='html'>I created an SSIS package today to archive a bunch of tables from a source server into one table on a destination server and then drop them on the source.  I wanted the process to be idempotent, such that the tables would either be fully archived and dropped or the whole thing rolled back.  Thus the process could be re-run if it failed in the middle without fear of duplicating data or prematurely dropping tables.&lt;br /&gt;&lt;br /&gt;The obvious solution was a transaction.  I set the TransactionOption property on my ForEach loop to Required and ran the package.  However, MSDTC was not cooperating, and I got this failure:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8yUEHkyTv1w/SXjSREVE8mI/AAAAAAAAAzs/Eyu_3Z0SiQs/s1600-h/SSIS+DTC+failure.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 176px; height: 400px;" src="http://3.bp.blogspot.com/_8yUEHkyTv1w/SXjSREVE8mI/AAAAAAAAAzs/Eyu_3Z0SiQs/s400/SSIS+DTC+failure.png" alt="" id="BLOGGER_PHOTO_ID_5294212552635773538" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;With the following error message: "The transaction has already been implicitly or explicitly committed or aborted."&lt;br /&gt;&lt;br /&gt;I checked MSDTC on both servers involved, and they each seemed to be set up correctly, albeit with slightly different settings.  MSDTC on my machine was also configured correctly.  Then I remembered that my desktop has &lt;span style="font-weight: bold;"&gt;Windows Firewall&lt;/span&gt; running.  Don't ask me why, it wasn't my idea, but I can't turn it off.&lt;br /&gt;&lt;br /&gt;So I added an exception to Windows Firewall for c:\windows\system32\msdtc.exe (port 135) and the package started working.  Hooray!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8yUEHkyTv1w/SXjUv9XLHaI/AAAAAAAAAz8/Ztm2DLe-QtQ/s1600-h/SSIS+DTC+success.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 172px; height: 400px;" src="http://1.bp.blogspot.com/_8yUEHkyTv1w/SXjUv9XLHaI/AAAAAAAAAz8/Ztm2DLe-QtQ/s400/SSIS+DTC+success.png" alt="" id="BLOGGER_PHOTO_ID_5294215282364718498" border="0" /&gt;&lt;/a&gt;&lt;span style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;/span&gt;Except that when I killed it midway through to simulate a network or SSIS host failure, it rolled back the whole thing.  I wanted the ForEach loop to commit each table load and drop as it went so that I wouldn't have to start from scratch if the package failed after a few tables.  So I created a Sequence container inside the ForEach container, set the TransactionOption to Required for that container, moved the Transfer and Drop tasks inside it, and set the TransactionOption to Supported for the ForEach.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-6301402893773719223?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/6301402893773719223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=6301402893773719223' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6301402893773719223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6301402893773719223'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2009/01/ssis-transactions-or-another-reason-to.html' title='SSIS transactions, or Another Reason To Hate Windows Firewall'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_8yUEHkyTv1w/SXjSREVE8mI/AAAAAAAAAzs/Eyu_3Z0SiQs/s72-c/SSIS+DTC+failure.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-266186015442450597</id><published>2009-01-07T12:10:00.001-08:00</published><updated>2009-01-07T12:14:36.737-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><title type='text'>sql_variant causes SSIS metadata validation error</title><content type='html'>Just a quick note about an error that stumped me for a minute. &lt;br /&gt;&lt;br /&gt;I was setting up a Lookup task in SSIS 2005 using the results of a SQL query as the lookup, but I kept getting the following error when attempting to create the column mappings:&lt;br /&gt;&lt;br /&gt;TITLE: Microsoft Visual Studio&lt;br /&gt;------------------------------&lt;br /&gt;&lt;br /&gt;Error at Load Position Limit Data [Lookup [49]]: SSIS Error Code DTS_E_OLEDBERROR.  An OLE DB error has occurred. Error code: 0x8000FFFF.&lt;br /&gt;&lt;br /&gt;Error at Load Position Limit Data [Lookup [49]]: The call to Lookup transform method, ReinitializeMetadata, failed.&lt;br /&gt;&lt;br /&gt;------------------------------&lt;br /&gt;ADDITIONAL INFORMATION:&lt;br /&gt;&lt;br /&gt;Exception from HRESULT: 0xC02090F0 (Microsoft.SqlServer.DTSPipelineWrap)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This didn't seem like a very helpful error, until I thought about what ReinitializeMetadata probably did, and then realized that my query selected a &lt;span style="font-weight: bold;"&gt;sql_variant&lt;/span&gt; column without casting it.  Casting the sql_variant to a more appropriate data type (varchar, in this case) resolved the error.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-266186015442450597?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/266186015442450597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=266186015442450597' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/266186015442450597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/266186015442450597'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2009/01/sqlvariant-causes-ssis-metadata.html' title='sql_variant causes SSIS metadata validation error'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-970696972492759800</id><published>2008-12-05T12:34:00.000-08:00</published><updated>2008-12-05T13:01:43.566-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JOINs'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='T-SQL'/><title type='text'>When an OUTER JOIN becomes an implicit INNER JOIN</title><content type='html'>I meant to blog about SQL PASS 2008, which I attended in Seattle and where I learned some good stuff, but I haven't had time.  Plus there were so many blogs and tweets from it that most of what I would have said was covered.  I will note that my favorite sessions were Itzik Ben-Gan's pre-conference session on Advanced T-SQL Querying and Bob Ward's talk about SQL Server memory.  If you get a chance to hear either of these guys talk, jump on it - they're both extremely sharp, and good presenters to boot.&lt;br /&gt;&lt;br /&gt;I'm posting this quick note because I had a question from one of our developers today regarding style for various joins.  He wanted to know whether a condition on a secondary table in a query should go in the ON clause or the WHERE clause.  This was my response:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I prefer to see conditions on the primary table in the WHERE clause, with conditions on the secondary tables in the ON clauses.  This is because a condition in the WHERE clause for the secondary table when using an OUTER JOIN will effectively convert that to an INNER JOIN, making it confusing to read the query.  However, putting that condition in the ON clause keeps the OUTER JOIN functioning as expected.  Does that make sense?&lt;br /&gt;&lt;br /&gt;Here’s an example with actual tables.&lt;br /&gt;&lt;br /&gt;Notice how the first and second queries return the same thing even though the second is a left outer join, because putting the t2 condition in the WHERE clause makes it required for the whole result set instead of just the join.  In the third query, the t2 condition is in the ON clause, making it only required for that join.  &lt;br /&gt;&lt;br /&gt;create table t1&lt;br /&gt;(alfa int,&lt;br /&gt;bravo int)&lt;br /&gt;&lt;br /&gt;create table t2&lt;br /&gt;(alfa int,&lt;br /&gt;charlie int)&lt;br /&gt;&lt;br /&gt;insert into t1 &lt;br /&gt;select 1, 2&lt;br /&gt;union all select 2, 3&lt;br /&gt;union all select 3, 4&lt;br /&gt;union all select 4, 5&lt;br /&gt;&lt;br /&gt;insert into t2&lt;br /&gt;select 1, 4&lt;br /&gt;union all select 2, 9&lt;br /&gt;union all select 3, 16&lt;br /&gt;&lt;br /&gt;select * from t1&lt;br /&gt;inner join t2&lt;br /&gt; on t1.alfa = t2.alfa&lt;br /&gt; and t2.charlie = 16&lt;br /&gt;where t1.alfa &lt; 5&lt;br /&gt;&lt;br /&gt;select * from t1&lt;br /&gt;left outer join t2&lt;br /&gt; on t1.alfa = t2.alfa&lt;br /&gt;where t1.alfa &lt; 5&lt;br /&gt;and t2.charlie = 16&lt;br /&gt;&lt;br /&gt;select * from t1&lt;br /&gt;left outer join t2&lt;br /&gt; on t1.alfa = t2.alfa&lt;br /&gt; and t2.charlie = 16&lt;br /&gt;where t1.alfa &lt; 5&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;drop table t1, t2&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-970696972492759800?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/970696972492759800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=970696972492759800' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/970696972492759800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/970696972492759800'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/12/when-outer-join-becomes-implicit-inner.html' title='When an OUTER JOIN becomes an implicit INNER JOIN'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-7953305387893787335</id><published>2008-10-28T11:03:00.001-07:00</published><updated>2008-10-30T12:49:53.097-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='SAN'/><category scheme='http://www.blogger.com/atom/ns#' term='RAID'/><category scheme='http://www.blogger.com/atom/ns#' term='IO'/><category scheme='http://www.blogger.com/atom/ns#' term='HP EVA'/><title type='text'>Optimizing tempdb and log disk performance</title><content type='html'>We implemented a new SAN fairly recently: an HP EVA.  In the enthusiasm to move to this new device, some tuning decisions were overlooked or made quickly, and are now being revisited.  For example, all the drives allocated to database servers were created on VRAID5 (essentially equivalent to RAID 5, refer to HP's &lt;a href="http://www11.itrc.hp.com/service/home/home.do?admit=109447626+1225381123601+28353475"&gt;IT Resource Center&lt;/a&gt; for the nuances).&lt;br /&gt;&lt;br /&gt;In general, it's a known fact that RAID 10 (aka VRAID1) outperforms RAID 5 (aka VRAID5) for write-heavy workloads, but at a higher cost per GB.  I wanted to revisit the cost-benefit analysis that led us to use RAID 5, because I've always used RAID 10 for at least logs and tempdb in the past, and for all SQL data when possible.&lt;br /&gt;&lt;br /&gt;To make sure that my analysis was relevant to our particular IO load, I planned to generate load on each type of drive using &lt;a href="http://www.iometer.org/"&gt;IOMeter&lt;/a&gt;, for which I would need to construct an appropriate workload.  I recorded a Counter Log with the following counters from each drive using Windows Performance Monitor from our main OLTP server over the course of several days.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Avg Disk Bytes/Read&lt;/li&gt;&lt;li&gt;Avg Disk Bytes/Write&lt;/li&gt;&lt;li&gt;Avg Disk Queue Length&lt;/li&gt;&lt;li&gt;Disk Reads/sec&lt;/li&gt;&lt;li&gt;Disk Writes/sec&lt;/li&gt;&lt;/ul&gt;Using these counters, I constructed a characteristic workload for each drive.&lt;br /&gt;&lt;br /&gt;To do this, I first bucketed each reading of Avg Disk Bytes/[Read, Write] into a size category (.5K, 1K, ...64K, 128K, etc.) and chose enough categories to add up to 80% of the total in order to determine what size IOs to generate.&lt;br /&gt;&lt;br /&gt;Then I added the averages of Disk Reads/sec and Disk Writes/sec in order to get the percentages of reads and writes against each disk, and used the average of Avg Disk Queue Length to determine how many IOs outstanding to queue up.&lt;br /&gt;&lt;br /&gt;Finally, I ran through this whole exercise again after deciding to filter for Disk Queues &gt; 2.  I did this because I figured that the SAN probably wasn't having any trouble when disk queues were low - RAID 5 vs RAID 1 would only show a difference in latency during those times.  The trouble comes when loads (for which disk queues are a proxy) are high; that's when you need maximum throughput and minimum response time.&lt;br /&gt;&lt;br /&gt;After all this, I came up with the following characteristic workloads for our system (yours may vary substantially):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;TEMPDB&lt;/span&gt;&lt;br /&gt;Reads - 2%&lt;br /&gt;- 68% 64K read size&lt;br /&gt;- 32% 8K read size&lt;br /&gt;Writes - 98%&lt;br /&gt;- 83% 64K write size&lt;br /&gt;- 17% 512B write size&lt;br /&gt;600 IOs outstanding&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;LOGS&lt;/span&gt;&lt;br /&gt;Reads - 36%&lt;br /&gt;- 87% 128K read size&lt;br /&gt;- 13% 1024K read size&lt;br /&gt;Writes -  64%&lt;br /&gt;- 81% 64K write size&lt;br /&gt;- 19% 16K write size&lt;br /&gt;4 IOs outstanding&lt;br /&gt;&lt;br /&gt;Next I worked with our Systems Engineering group to create a VRAID5 and a VRAID1 drive of the same size and attached both to the same server.  I created Access Specifications with IOMeter for each workload shown above (see image below), and then ran those Access Specifications against each drive with the requisite number of IOs outstanding.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8yUEHkyTv1w/SQoJE9NX1NI/AAAAAAAAAww/fyLZnBeAdwQ/s1600-h/IOMeter+logs+access+spec.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 160px;" src="http://3.bp.blogspot.com/_8yUEHkyTv1w/SQoJE9NX1NI/AAAAAAAAAww/fyLZnBeAdwQ/s400/IOMeter+logs+access+spec.png" alt="" id="BLOGGER_PHOTO_ID_5263029095290623186" border="0" /&gt;&lt;/a&gt;This yielded some fairly conclusive results.  I won't post the actual throughput numbers, but here are the margins by which VRAID1 outperformed VRAID5 for each workload:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;TEMPDB&lt;/span&gt;&lt;br /&gt; &lt;table style="border-collapse: collapse; width: 206pt;" width="274" border="0" cellpadding="0" cellspacing="0"&gt;&lt;col style="width: 48pt;" span="2" width="64"&gt;  &lt;col style="width: 110pt;" width="146"&gt;  &lt;tbody&gt;&lt;tr style="height: 15pt;" height="20"&gt;   &lt;td class="xl65" style="height: 15pt; width: 48pt;" width="64" height="20"&gt;IOPS&lt;/td&gt;   &lt;td class="xl65" style="width: 48pt;" width="64"&gt;MB/s&lt;/td&gt;   &lt;td class="xl65" style="width: 110pt;" width="146"&gt;Avg IO Response Time&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td class="xl66" style="height: 15pt;" align="right" height="20"&gt;117.65%&lt;/td&gt;   &lt;td class="xl66" align="right"&gt;117.55%&lt;/td&gt;   &lt;td class="xl66" align="right"&gt;51.48%&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;LOGS&lt;/span&gt;&lt;br /&gt; &lt;table style="border-collapse: collapse; width: 206pt;" width="274" border="0" cellpadding="0" cellspacing="0"&gt;&lt;col style="width: 48pt;" span="2" width="64"&gt;  &lt;col style="width: 110pt;" width="146"&gt;  &lt;tbody&gt;&lt;tr style="height: 15pt;" height="20"&gt;   &lt;td class="xl65" style="height: 15pt; width: 48pt;" width="64" height="20"&gt;IOPS&lt;/td&gt;   &lt;td class="xl65" style="width: 48pt;" width="64"&gt;MB/s&lt;/td&gt;   &lt;td class="xl65" style="width: 110pt;" width="146"&gt;Avg IO Response Time&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td class="xl66" style="height: 15pt;" align="right" height="20"&gt;80.05%&lt;/td&gt;   &lt;td class="xl66" align="right"&gt;65.63%&lt;/td&gt;   &lt;td class="xl66" align="right"&gt;39.69%&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;So according to my testing, VRAID1 is vastly superior for these types of workloads, to the point where it's probably worth the higher cost per GB.  We'll see how this bears out in further testing and in real-world usage shortly...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-7953305387893787335?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/7953305387893787335/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=7953305387893787335' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7953305387893787335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7953305387893787335'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/10/optimizing-tempdb-and-log-disk.html' title='Optimizing tempdb and log disk performance'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_8yUEHkyTv1w/SQoJE9NX1NI/AAAAAAAAAww/fyLZnBeAdwQ/s72-c/IOMeter+logs+access+spec.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1465720752085289226</id><published>2008-10-27T09:49:00.000-07:00</published><updated>2009-01-07T12:16:19.900-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='VMWare'/><category scheme='http://www.blogger.com/atom/ns#' term='SSDs'/><category scheme='http://www.blogger.com/atom/ns#' term='clusters'/><title type='text'>Using local disks in a cluster</title><content type='html'>With the advent of (relatively) cheap, fast Solid State Disks, DBAs everywhere are realizing that they could potentially see huge performance gains by incorporating these new disks into their database servers.  This is straightforward if you've got a monolithic box: buy 2 SSDs, create a new RAID 1, move tempdb and/or logs onto it, restart SQL, shake well, and watch your IO waits go to 0!  Hopefully, anyway.&lt;br /&gt;&lt;br /&gt;However, if you've got a cluster, things are a bit trickier.  The SAN vendors are still ramping up their SSD support, so it can be difficult to get an SSD into a shared storage enclosure unless you roll your own.  Especially if you pick up one of the most promising new disks, the FusionIO &lt;a href="http://www.fusionio.com/Products.aspx"&gt;ioDrive&lt;/a&gt;. This disk gets attached to a PCIe bus directly rather than a SAS or SATA backplane, so it can't be put into most commercially available shared storage devices (SANs, NASs, etc.).&lt;br /&gt;&lt;br /&gt;Even so, we were sufficiently impressed by the IO stats on this disk to pick up a couple of them, but we still wanted to put them in our production cluster.  We can't use them for shared data, obviously, as the data wouldn't persist between machines.  But in theory they could be perfect for tempdb, which gets wiped out on each restart and so only needs to see the same path on each machine.  I figured there was probably a way to get Microsoft Cluster Services to see the local SSDs on each machine as the same disk.&lt;br /&gt;&lt;br /&gt;To test this theory, we (I and coworker Doug H.) took a pair of virtual machines, added drives to simulate a standard local disk, &lt;a href="http://sqladvice.com/blogs/repeatableread/archive/2005/08/01/4273.aspx"&gt;shared SAN storage&lt;/a&gt;, and the new SSD, built them into a cluster, and installed SQL Server 2005 on the R: drive.&lt;br /&gt;&lt;br /&gt;Disk 0 (C:) - local - boot disk&lt;br /&gt;Disk 1 (Q:) - shared - quorum&lt;br /&gt;Disk 2 (R:) - shared - SQL data&lt;br /&gt;Disk 3 (D:) - local - simulated SSD&lt;br /&gt;&lt;br /&gt;When the VMs were initially configured, the fake SSDs were created on the same SCSI bus as the boot disk.  The cluster administrator quickly informed us that this would not fly - disks on the same bus as the boot disk cannot be used as shared resources.  So we moved the D: drives to a new bus, separate from both the C: (simulated backplane) and Q:/R: (simulated SAN) drives.&lt;br /&gt;&lt;br /&gt;The next step was to add the D: drive to the cluster.  I assumed this wouldn't work without some hacking, but I decided to try a "baseline" attempt without any modifications. The Cluster Admin New Resource wizard allowed me to add the D: drive on one of the nodes, but it wouldn't come online.  So much for the baseline attempt.&lt;br /&gt;&lt;br /&gt;I knew that Windows 2003 (though maybe not 2008) clustering relies on disk signatures to identify disks for cluster operations, so I decided to synchronize the signatures of the two fake SSDs.  To this end, I found a utility - &lt;a href="http://mbrwizard.com/"&gt;MBRWizard&lt;/a&gt; - that would let me manually set the signature of an MBR disk.&lt;br /&gt;&lt;br /&gt;Using this utility, I found the signature of the D: drive on machine #1:&lt;br /&gt;&lt;br /&gt;mbrwiz /Disk=3 /Signature&lt;br /&gt;&lt;br /&gt;and then overwrote the signature of the D: drive on machine #2:&lt;br /&gt;&lt;br /&gt;mbrwiz /Disk=3 /Signature=xxxxxxxx&lt;br /&gt;&lt;br /&gt;Then I added the disk as a cluster resource again, and brought it online.  Success!  Failover worked, too, so I failed the SQL Server group (Group 0 in the image below) back and forth between nodes and created a Data directory on each D: drive.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_8yUEHkyTv1w/SQYMFN2b27I/AAAAAAAAAwo/S6iTNB77bec/s1600-h/SSDClusterTest.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 140px;" src="http://4.bp.blogspot.com/_8yUEHkyTv1w/SQYMFN2b27I/AAAAAAAAAwo/S6iTNB77bec/s400/SSDClusterTest.png" alt="" id="BLOGGER_PHOTO_ID_5261906498385861554" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The next step was to make sure it worked with SQL Server.  I took SQL offline, added Disk D: as a dependency, and brought it back up.  Then I altered tempdb's location to use the D: drive after a restart.&lt;br /&gt;&lt;br /&gt;alter database tempdb&lt;br /&gt;modify file (NAME=tempdev, FILENAME = 'D:\Data\tempdb.mdf')&lt;br /&gt;GO&lt;br /&gt;alter database tempdb&lt;br /&gt;modify file (NAME=templog, FILENAME = 'D:\Data\templog.ldf')&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;Finally I took SQL offline and brought it back up, with fingers crossed.  And it worked!  Failover worked too.&lt;br /&gt;&lt;br /&gt;So my proof of concept for using a local SSD in a cluster (for tempdb only!) was successful.  Stay tuned to see if it works in the real world.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1465720752085289226?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1465720752085289226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1465720752085289226' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1465720752085289226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1465720752085289226'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/10/using-local-disks-in-cluster.html' title='Using local disks in a cluster'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_8yUEHkyTv1w/SQYMFN2b27I/AAAAAAAAAwo/S6iTNB77bec/s72-c/SSDClusterTest.png' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5469849197481939609</id><published>2008-10-03T11:48:00.000-07:00</published><updated>2008-10-03T12:58:44.945-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='buildbot'/><category scheme='http://www.blogger.com/atom/ns#' term='windows service'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Running a Buildbot buildslave as a Windows service</title><content type='html'>&lt;a href="http://buildbot.net/trac"&gt;Buildbot&lt;/a&gt; is an open source continuous integration system written in Python.  We use it to automate the builds on one of the projects I work on, and in general, it's cool.  Pretty easy to set up (just make sure you look at &lt;span style="font-style: italic;"&gt;every&lt;/span&gt; setting in the config file), comes with its own simple but handy web interface, and allows quick configuration of multiple "builders" and "buildslaves."&lt;br /&gt;&lt;br /&gt;However, like most open source projects, it's written for and by *nix users and doesn't have full Windows support.  Fortunately, Mark Hammond (of &lt;a href="http://python.net/crew/mhammond/win32/"&gt;win32api&lt;/a&gt; fame) deigned to write the buildbot_service.py file, which allows installation of the Buildbot buildmaster as a service.&lt;br /&gt;&lt;br /&gt;But despite this, there's no out-of-the-box way to run a build&lt;span style="font-style: italic;"&gt;slave&lt;/span&gt; as a service.  There are a few other &lt;a href="http://www.stolennotebook.com/anthony/2006/07/03/running-buildbot-as-a-windows-xp-service/"&gt;hardy&lt;/a&gt; &lt;a href="http://ascendwiki.cheme.cmu.edu/BuildBot"&gt;souls&lt;/a&gt; out there who have figured out various methods for accomplishing this, and I am indebted to their guides as helpful starting points.  But I didn't like all the registry hacking and configuration steps, so I went another way.  Hammond's buildbot_service.py scares me, but I gleaned enough from it to put together my own buildslave_service.py.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8yUEHkyTv1w/SOZ4lGfZAhI/AAAAAAAAAvo/wh5LN9a4U14/s1600-h/BuildslaveService.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_8yUEHkyTv1w/SOZ4lGfZAhI/AAAAAAAAAvo/wh5LN9a4U14/s400/BuildslaveService.png" alt="" id="BLOGGER_PHOTO_ID_5253018594167030290" border="0" /&gt;&lt;/a&gt;It's not terribly full-featured, and it requires reinstallation if any settings are changed, but it's compact, effective, and easy to install.&lt;br /&gt;&lt;br /&gt;Steps:&lt;br /&gt;1) Copy code below, correct spacing that Blogger's HTML window stripped out, change paths as appropriate, save as buildslave_service.py.&lt;br /&gt;2) Install the service (w/ optional parameter for automatic startup if you want):&lt;br /&gt;python buildslave_service.py install [--startup=auto]&lt;br /&gt;3) Start the service:&lt;br /&gt;net start Buildbot_Buildslave&lt;br /&gt;(or use the Services mmc snap-in)&lt;br /&gt;&lt;br /&gt;And that's it!  Easier than all the registry mess and downloading Win2003 resource packs, no?&lt;br /&gt;&lt;br /&gt;""" buildslave_service.py&lt;br /&gt;&lt;br /&gt;Original Author: Ira Pfeifer&lt;br /&gt;Email: ipfeifer -dot- tech -at- gmail&lt;br /&gt;"""&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;import os&lt;br /&gt;import subprocess&lt;br /&gt;import win32serviceutil&lt;br /&gt;import win32service&lt;br /&gt;import win32event&lt;br /&gt;import win32api&lt;br /&gt;import time&lt;br /&gt;&lt;br /&gt;from buildbot.scripts import runner&lt;br /&gt;from buildbot.scripts.startup import start&lt;br /&gt;&lt;br /&gt;# change paths as appropriate&lt;br /&gt;slavepath = "c:\\buildbot\\buildslave"&lt;br /&gt;homepath = "\\"&lt;br /&gt;os.environ['HOMEDRIVE'] = "C:"&lt;br /&gt;os.environ['HOMEPATH'] = homepath&lt;br /&gt;os.environ['PATH'] = ";".join([&lt;br /&gt;   r"C:\Python25"&lt;br /&gt;   ,r"C:\Python25\Scripts"&lt;br /&gt;])&lt;br /&gt;&lt;br /&gt;class BuildSlaveService(win32serviceutil.ServiceFramework):&lt;br /&gt;_svc_name_ = "BuildBot_BuildSlave"&lt;br /&gt;_svc_display_name_ = "BuildBot BuildSlave"&lt;br /&gt;_svc_description_ = "Buildbot slave based in " + slavepath&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def __init__(self, args):&lt;br /&gt;   win32serviceutil.ServiceFramework.__init__(self, args)&lt;br /&gt;   self.stop_event = win32event.CreateEvent(None, 0, 0, None)&lt;br /&gt;&lt;br /&gt;def SvcDoRun(self):&lt;br /&gt;   # The service starts a subprocess that will run the actual buildbot&lt;br /&gt;   # so that it can be stopped by simply killing off the subprocess.&lt;br /&gt;   self.child = subprocess.Popen(["python",&lt;br /&gt;       __file__,&lt;br /&gt;       "start"])&lt;br /&gt;   isAlive = True&lt;br /&gt;   while isAlive:&lt;br /&gt;       time.sleep(10)&lt;br /&gt;&lt;br /&gt;def SvcStop(self):&lt;br /&gt;&lt;br /&gt;   self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)&lt;br /&gt;   handle = win32api.OpenProcess(1,0,self.child.pid)&lt;br /&gt;   # returns exit code - wrap w/ error handling?&lt;br /&gt;   win32api.TerminateProcess(handle, 0)&lt;br /&gt;   win32api.CloseHandle(handle)&lt;br /&gt;   isAlive = False&lt;br /&gt;   self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)&lt;br /&gt;   win32.SetEvent(self.hWaitStop)&lt;br /&gt;&lt;br /&gt;SvcShutdown = SvcStop&lt;br /&gt;&lt;br /&gt;def start_buildslave():&lt;br /&gt;config = runner.Options()&lt;br /&gt;config.parseOptions(['start',slavepath])&lt;br /&gt;so = config.subOptions&lt;br /&gt;start(so)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;if len(sys.argv) &gt; 1 and sys.argv[1] == "start":&lt;br /&gt;   start_buildslave()&lt;br /&gt;else:&lt;br /&gt;   win32serviceutil.HandleCommandLine(BuildSlaveService)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5469849197481939609?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5469849197481939609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5469849197481939609' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5469849197481939609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5469849197481939609'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/10/running-buildbot-buildslave-as-windows.html' title='Running a Buildbot buildslave as a Windows service'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_8yUEHkyTv1w/SOZ4lGfZAhI/AAAAAAAAAvo/wh5LN9a4U14/s72-c/BuildslaveService.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8013446086433712643</id><published>2008-09-28T09:11:00.000-07:00</published><updated>2009-05-01T09:38:01.946-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='tempdb'/><category scheme='http://www.blogger.com/atom/ns#' term='affinity mask'/><title type='text'>CPU Affinity Masking plus High CPU = Login Timeouts</title><content type='html'>Recently we saw an alarming issue with one of our database servers. Under heavy but not prohibitive load (60-80% CPU), it stopped accepting new connections intermittently. Obviously this is bad for any server, especially one that handles thousands of client connections simultaneously.&lt;br /&gt;&lt;br /&gt;Some of the hard drives were under heavy load, especially tempdb, but another anomaly was a long-running query using many linked server connections (11!) that had been killed but was stuck in rollback several hours later. It was consuming near 100% of the cycles on one CPU core. We tried a variety of the usual DBA tricks to get rid of this spid, but nothing worked. It wasn't clear to us how this could cause the server to stop accepting connections, however.&lt;br /&gt;&lt;br /&gt;Another oddity was the appearance in the System logs of messages like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(255,0,0)"&gt;The time stamp counter of CPU on scheduler id 2 is not synchronized with other CPUs.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I asked our Systems guys about this, and they said that this had been noticed a few months ago and a workaround had been put in place as per &lt;a href="http://support.microsoft.com/kb/931279"&gt;KB 931279&lt;/a&gt; - the CPU affinity mask had been set in SQL Server.&lt;br /&gt;&lt;br /&gt;Hmm.&lt;br /&gt;&lt;br /&gt;This happened again a week later, minus the spid stuck in rollback, but with one CPU slammed at 100% again. We had engaged Microsoft PSS to assist with the problem, but so far all they had told us was that we had tempdb IO issues, which we knew. (&lt;a href="http://www.dvnation.com/"&gt;DVNation&lt;/a&gt;, please finish the Windows drivers for your IODrives so we can use them for tempdb!)&lt;br /&gt;&lt;br /&gt;So here's my theory, cooked up with one of the other DBAs: the login issues are being caused by the combination of affinity masking and one CPU at 100%. This could happen because schedulers are affinitized by the mask to a single CPU, making them unable to hop CPUs when one is under heavy load. User logins round-robin between schedulers, so if a scheduler is stuck to a single CPU and that CPU is not making enough cycles available to log someone in, eventually the login will timeout and fail.&lt;br /&gt;&lt;br /&gt;Plausible? Anyone else seen this kind of issue?&lt;br /&gt;&lt;br /&gt;UPDATE:&lt;br /&gt;&lt;br /&gt;I was right.  After removing the affinity masking, we no longer saw login timeouts, even when the server was near 100% CPU load.  Be careful with those affinity masks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8013446086433712643?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8013446086433712643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8013446086433712643' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8013446086433712643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8013446086433712643'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/09/long-query-rollback-causes-cpu.html' title='CPU Affinity Masking plus High CPU = Login Timeouts'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-6287419631317803260</id><published>2008-09-22T08:57:00.000-07:00</published><updated>2008-09-29T06:19:29.989-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pstools'/><category scheme='http://www.blogger.com/atom/ns#' term='psexec'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='sysinternals'/><title type='text'>psexec Permission denied error</title><content type='html'>In the course of my DBA and software dev tasks, I make extensive use of Mark Russinovich's excellent &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896649.aspx"&gt;PSTools&lt;/a&gt;.  Today I ran across an odd error while running a remote command using psexec.  Filenames have been changed, obviously, but here's the gist of it:&lt;br /&gt;&lt;br /&gt;&gt; psexec \\remotemachine python \\fileserver\script.py param1 param2&lt;br /&gt;&lt;br /&gt;python: can't open file '\\fileserver\script.py': [Errno 13] Permission denied&lt;br /&gt;&lt;br /&gt;So it was obviously opening python, which I double-checked by running with the -i option and checking the remote machine's desktop using VNC Viewer.  The python shell was opening successfully, but it couldn't access the file server.   Executing the script directly from the remote machine's command line worked fine.&lt;br /&gt;&lt;br /&gt;Then I realized that this was the same issue that one gets from too (two? ;) many linked server hops using integrated authentication - it's a two-hop Kerberos problem.  Google that if you don't know what I'm talking about.  Fortunately, psexec offers the option of passing a username and password, and as soon as I added those options, my command executed successfully.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-6287419631317803260?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/6287419631317803260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=6287419631317803260' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6287419631317803260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6287419631317803260'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/09/psexec-permission-denied-error.html' title='psexec Permission denied error'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2614670964136402686</id><published>2008-09-16T12:03:00.000-07:00</published><updated>2008-09-22T09:10:45.704-07:00</updated><title type='text'>DBA rant</title><content type='html'>I'm not big on posting links, but this is the best &lt;a href="http://bonesmoses.org/view.php?id=256"&gt;angry DBA post&lt;/a&gt; I've read in some time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2614670964136402686?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2614670964136402686/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2614670964136402686' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2614670964136402686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2614670964136402686'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/09/dba-rant.html' title='DBA rant'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8169734051797084363</id><published>2008-09-09T12:55:00.001-07:00</published><updated>2008-09-09T13:39:31.204-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='tcp/ip'/><title type='text'>SSIS Data Flow Task Error caused by too many Data Flow tasks</title><content type='html'>I just threw together a very basic SQL 2005 SSIS package, the main component of which is a Data Flow task with 25 sub-flows.  The flows are very simple, just direct transfers of a table on one server to the same table name on another server.  As an aside, it took WAY too long to create this package - for each little flow, I had to select the source connection, wait for it to populate the table drop-down, then scroll through that drop-down through hundreds of tables to find the one I wanted, then do it again for the destination.  This could be better in a number of ways:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Allow typing in the table field.  It would have been much quicker to allow me to type or copy and paste the table name rather than waiting for the drop-down and then scrolling through it.  50 times.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Improve copy and paste of flow tasks.  If I could have constructed one and duplicated it 25 times, it would have been much quicker, but when I attempted that, I got strange warnings about field truncation that were cleared up only by deleting the source and re-creating it.&lt;/li&gt;&lt;li&gt;Create a wizard that facilitates auto-generating this kind of simple package better than the Transfer Objects wizard.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Maybe one or more of these has been implemented in SQL 2008, but I can't use that yet, since my office has no plans to upgrade our SSIS runtime any time soon.&lt;br /&gt;&lt;br /&gt;Anyway, when attempting to execute the package, I was consistently getting a failure from one flow with this error:&lt;br /&gt;&lt;br /&gt;TCP Provider: An existing connection was forcibly closed by the remote host&lt;br /&gt;&lt;br /&gt;This didn't make much sense to me, as it worked fine when run by itself.  I found &lt;a href="http://msdn.microsoft.com/en-us/library/ms189083.aspx"&gt;this article&lt;/a&gt; and added that registry key, but it did not fix the problem (although it did seem to increase throughput).&lt;br /&gt;&lt;br /&gt;Then I noticed that the two largest flows in the Data Flow task (on the order of millions of rows) were executing at the time when the problem task was throwing an error.  I thought SSIS would be able to handle the sequencing of parallel tasks, but I decided to enforce my own execution order by placing the two large flows in a separate Data Flow task.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_8yUEHkyTv1w/SMbetmxhJRI/AAAAAAAAAZc/2fdxHO2Dtkw/s1600-h/data+flow+tasks.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_8yUEHkyTv1w/SMbetmxhJRI/AAAAAAAAAZc/2fdxHO2Dtkw/s400/data+flow+tasks.png" alt="" id="BLOGGER_PHOTO_ID_5244123691203241234" border="0" /&gt;&lt;/a&gt;Voila. Works fine.  So if you're having issues with an overpopulated Data Flow task throwing that TCP error, one simple workaround is to manually sequence/reduce the parallel execution of the tasks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8169734051797084363?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8169734051797084363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8169734051797084363' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8169734051797084363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8169734051797084363'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/09/ssis-data-flow-task-error-too-many-data.html' title='SSIS Data Flow Task Error caused by too many Data Flow tasks'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_8yUEHkyTv1w/SMbetmxhJRI/AAAAAAAAAZc/2fdxHO2Dtkw/s72-c/data+flow+tasks.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5962227768683188182</id><published>2008-09-08T14:04:00.000-07:00</published><updated>2008-09-08T16:59:30.419-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>Programming Languages I know</title><content type='html'>To pick up the latest blog mini-meme (courtesy of &lt;a href="http://coreygoldberg.blogspot.com/2008/09/list-of-programming-languages-i-know.html"&gt;Corey Goldberg&lt;/a&gt;), here's The List of programming languages I have learned:&lt;br /&gt;&lt;br /&gt;1. AppleScript&lt;br /&gt;2. C&lt;br /&gt;3. Java&lt;br /&gt;4. Lisp (Scheme)&lt;br /&gt;5. C++&lt;br /&gt;6. JavaScript&lt;br /&gt;7. ANSI SQL*&lt;br /&gt;8. PHP&lt;br /&gt;9. T-SQL&lt;br /&gt;10. VBScript&lt;br /&gt;11. C#&lt;br /&gt;12. Python&lt;br /&gt;&lt;br /&gt;Kind of a strange order, no?  Mostly driven by expediency, except Scheme and C++, which I learned in college.&lt;br /&gt;&lt;br /&gt;UPDATE: Dan points out that ANSI SQL is not Turing complete and should be asterisked, so I guess I'm down to 11.5.  Let's see your monster list, Dan - mcfunley.com has been pretty quiet lately.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5962227768683188182?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5962227768683188182/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5962227768683188182' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5962227768683188182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5962227768683188182'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/09/programming-languages-i-know.html' title='Programming Languages I know'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5335887340919410817</id><published>2008-09-05T10:41:00.000-07:00</published><updated>2008-09-05T10:46:12.511-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='dts'/><title type='text'>DTS Editing doesn't work in SQL 2008?</title><content type='html'>I've been running the SQL 2008 RTM for a few weeks now, and generally it works fine.  But today I needed to open an ancient DTS package (it's not from my team, all our stuff is SSIS), and couldn't do it.  First it told me I needed the SQL 200&lt;span style="font-weight: bold;"&gt;5&lt;/span&gt; Backwards Compatibility components.  "That's odd," I thought, "I could have sworn I installed all of that when I ran the SQL 2008 setup.  And why is it asking for the 2005 components?"&lt;br /&gt;&lt;br /&gt;It appears that Microsoft has simply updated the 2005 BC component install to work with 2008.  Fine.  I installed that, and tried to open the package again.  No dice.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8yUEHkyTv1w/SMFwFGMV8tI/AAAAAAAAAYM/mATJKN-LMzE/s1600-h/2000+DTS+Designer.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_8yUEHkyTv1w/SMFwFGMV8tI/AAAAAAAAAYM/mATJKN-LMzE/s400/2000+DTS+Designer.png" alt="" id="BLOGGER_PHOTO_ID_5242594674100007634" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;So I went to find those components.  Found the package, installed it... to no effect whatsoever!  I still get the same message!  Note to Microsoft: if you don't want me to edit DTS packages in 2008 and have deprecated that functionality entirely, fine.  Just TELL ME instead of popping up worthless error messages whose instructions I follow to no avail.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5335887340919410817?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5335887340919410817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5335887340919410817' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5335887340919410817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5335887340919410817'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/09/dts-editing-doesnt-work-in-sql-2008.html' title='DTS Editing doesn&apos;t work in SQL 2008?'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_8yUEHkyTv1w/SMFwFGMV8tI/AAAAAAAAAYM/mATJKN-LMzE/s72-c/2000+DTS+Designer.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5217168305786520316</id><published>2008-08-26T13:36:00.000-07:00</published><updated>2008-09-22T09:10:13.498-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='float'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Float comparison tolerance</title><content type='html'>Had the age-old problem with significant figures when comparing floats in Python today, and came up with this little function to deal with it.  It ensures that the two values are equal down to 10 significant figures, no matter at what scale they start.  This is as opposed to the conventional test, which checks at a fixed scale (e.g. return abs(a - b) &lt; 1e-10).&lt;br /&gt;&lt;br /&gt;def equal(a, b):&lt;br /&gt;  return abs(a - b) &lt;= abs(a - b)/10000000000&lt;br /&gt;&lt;br /&gt;Testing:&lt;br /&gt;&lt;br /&gt;a = .0000000000000000837&lt;br /&gt;b = .00000000000000004315&lt;br /&gt;c = a + 100&lt;br /&gt;d = b + 100&lt;br /&gt;&lt;br /&gt;equal(a,b)&lt;br /&gt;False&lt;br /&gt;&lt;br /&gt;equal(b,a)&lt;br /&gt;False&lt;br /&gt;&lt;br /&gt;equal(c,d)&lt;br /&gt;True&lt;br /&gt;&lt;br /&gt;equal(d,c)&lt;br /&gt;True&lt;br /&gt;&lt;br /&gt;equal(1,1)&lt;br /&gt;True&lt;br /&gt;&lt;br /&gt;(Of course, we wound up defining a hard limit, 1e-10, and not using my function, but I still thought it was clever.)&lt;br /&gt;&lt;br /&gt;UPDATE: Yes, I recognize that this is hardly a new problem or solution, but it's MY BLOG and I mostly use it as a memory aid anyway - outside readers are incidental (which is a good thing, given my Google Analytics stats).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5217168305786520316?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5217168305786520316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5217168305786520316' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5217168305786520316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5217168305786520316'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/08/float-comparison-tolerance.html' title='Float comparison tolerance'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-7509625046089620014</id><published>2008-07-18T13:13:00.001-07:00</published><updated>2008-07-18T13:16:24.582-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linked servers'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><title type='text'>Automated linked server test</title><content type='html'>Got a big production event scheduled, so I wrote this quick automated test to be incorporated into the post-event testing. I'll probably improve on it incrementally as I notice shortcomings, but at the moment it's just a basic test of data access via all linked servers set up on a machine.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/*** Linked Server Test ***/ &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;declare @linked table (name sysname, done bit, retval int)&lt;br /&gt;declare @srvr sysname&lt;br /&gt;declare @sql varchar(255)&lt;br /&gt;declare @retval int&lt;br /&gt;insert into @linked select name, 0 as done, NULL as retval from sys.servers&lt;br /&gt;while exists (select 1 from @linked where done = 0)&lt;br /&gt;begin&lt;br /&gt;select top 1 @srvr = name from @linked where done = 0&lt;br /&gt;begin try&lt;br /&gt;exec @retval = sp_testlinkedserver @srvr&lt;br /&gt;end try&lt;br /&gt;begin catch&lt;br /&gt;set @retval = sign(@@error)&lt;br /&gt;end catch&lt;br /&gt;exec(@sql)&lt;br /&gt;update @linked set done = 1, retval = @retval where name = @srvr&lt;br /&gt;end&lt;br /&gt;select * from @linked&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-7509625046089620014?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/7509625046089620014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=7509625046089620014' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7509625046089620014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7509625046089620014'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/07/automated-linked-server-test.html' title='Automated linked server test'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8623672387156548114</id><published>2008-07-14T10:12:00.000-07:00</published><updated>2008-07-14T10:33:27.096-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyodbc'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>pyodbc returns an int instead of rows in a cursor</title><content type='html'>Just a quick note about pyodbc: if you're getting a TypeError from a pyodbc cursor because it's an int instead of a rowset, it's probably because the proc or query being called is returning extra info or messages.  Try turning off anything that's returning extraneous info, like ANSI_WARNINGS.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8623672387156548114?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8623672387156548114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8623672387156548114' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8623672387156548114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8623672387156548114'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/07/pyodbc-returns-int-instead-of-rows-in.html' title='pyodbc returns an int instead of rows in a cursor'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-6046138374931675634</id><published>2008-06-17T07:33:00.001-07:00</published><updated>2008-08-12T06:08:11.778-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server installation'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2008'/><title type='text'>SQL 2008 installation problems</title><content type='html'>Several of us at my office had issues installing SQL 2008 RC0 - the installer kept failing the "Restart computer" check.&lt;br /&gt;&lt;br /&gt;So I started digging through the registry to find the culprit flag... when this forum post turned up and pointed me to exactly the right place.&lt;br /&gt;&lt;br /&gt;http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3492057&amp;amp;SiteID=1&lt;br /&gt;&lt;br /&gt;Turns out our virus scanning software always posts a pending file rename, which SQL setup interprets as the computer needing a reboot.  I cleared these values and the installer ran fine.&lt;br /&gt;&lt;br /&gt;UPDATE: Had the same problem with SQL 2008 RTM.  Fix works for that too, and probably for many other installers that refuse to start due to a pending file operation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-6046138374931675634?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/6046138374931675634/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=6046138374931675634' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6046138374931675634'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/6046138374931675634'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/06/sql-2008-rc0-installation-problems.html' title='SQL 2008 installation problems'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1674478796338099659</id><published>2008-06-10T10:32:00.000-07:00</published><updated>2008-06-10T10:43:45.377-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyodbc'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Returning rows from a stored procedure with pyodbc, pt 2</title><content type='html'>Pyodbc really doesn't like extraneous information to be returned with its (ONE AND ONLY ONE!) result set from a stored procedure.&lt;br /&gt;&lt;br /&gt;In my latest fight with pyodbc, I had a stored proc returning a rowset with a few thousand rows.  This worked fine most of the time, except in a few cases with certain input parameters.  In those cases, the cursor returned by execute() would contain an int, so any cursor method I called on it would break.&lt;br /&gt;&lt;br /&gt;At first I thought I might have hit some kind of row size limit or rowcount limit, but realized the result set wasn't big enough for that to be the case.  The proc wasn't throwing off any errors when run in SQL Management Studio with the same input parameters, so that wasn't the problem.&lt;br /&gt;&lt;br /&gt;Then I noticed that  it was returning a single warning message in the Messages tab.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;" class="searchTerm"&gt;Warning&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;span style="font-weight: bold;" class="searchTerm"&gt;Null&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold;" class="searchTerm"&gt;value&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; is eliminated by an aggregate or other SET operation.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;This is a fairly common warning in SQL land, so I hadn't paid any attention to it.  But it is possible to suppress, using the following statement:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;SET ANSI_WARNINGS OFF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Sure enough, this did the trick.  The moral of this story (just like last time) is that pyodbc wants a single rowset and that's it; returning any data in any of the alternate ODBC channels seems to break it, or at least, not yield the cursor in the result set that I expected.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1674478796338099659?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1674478796338099659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1674478796338099659' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1674478796338099659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1674478796338099659'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/06/returning-rows-from-stored-procedure.html' title='Returning rows from a stored procedure with pyodbc, pt 2'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2314122085663149232</id><published>2008-06-07T09:24:00.000-07:00</published><updated>2008-06-07T09:43:11.902-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows Vista'/><category scheme='http://www.blogger.com/atom/ns#' term='User Access Control'/><title type='text'>Speeding up Vista User Access Control (UAC)</title><content type='html'>My HP laptop (tx1210) runs Vista Home Premium, and I'm constantly performing actions on it that pop up the User Access Control window.  I don't have a problem with this in and of itself, as I've read Microsoft's side of the argument and I'm willing to give them the benefit of the doubt and assume that this does actually provide some additional security. &lt;br /&gt;&lt;br /&gt;That said, it's slow as hell.&lt;br /&gt;&lt;br /&gt;The UAC popup isn't bad on my monster desktop, which has a top-end Core 2 Duo, 4 GB of RAM, and a decent video card, but it takes FOREVER on my laptop - probably 3-5 seconds to black out the screen and pop up the prompt, and another 3-5 to black out the screen again and return me to what I was doing.  This is unacceptable in 2008. &lt;br /&gt;&lt;br /&gt;After reading a few unhelpful posts directing me to disable UAC completely, I found one that mentioned that it wasn't as slow with Aero (the pretty transparency and other visual effects package in the higher versions of Vista) disabled.  So I opened the Performance Information &amp;amp; Tools feature in the Control Panel and selected Adjust Visual Effects.  After turning off the vast majority (I left &lt;span style="font-style: italic;"&gt;Use visual styles on windows and buttons&lt;/span&gt; because I just couldn't bear to look at the old grey XP-style taskbar any more), guess what?  UAC is now lightning-fast and doesn't bother me at all. &lt;br /&gt;&lt;br /&gt;I'll probably try re-enabling a few more settings and find the balance between speed and graphical sugar, but disabling most of the visual effects seems to have done the trick, and is already improving my Vista experience dramatically.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2314122085663149232?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2314122085663149232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2314122085663149232' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2314122085663149232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2314122085663149232'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/06/speeding-up-vista-user-access-control.html' title='Speeding up Vista User Access Control (UAC)'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-7851817392542086243</id><published>2008-05-06T14:13:00.000-07:00</published><updated>2008-05-06T14:37:22.789-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ftp'/><category scheme='http://www.blogger.com/atom/ns#' term='SmartFTP'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Python's subprocess doesn't like SmartFTP</title><content type='html'>Well, that was a frustrating afternoon.  I was trying to automate the update process described in my &lt;a href="http://nyc-dba.blogspot.com/2008/05/how-to-break-your-ftp-client.html"&gt;previous post&lt;/a&gt; - an executable that uses SmartFTP's COM library to connect to an FTP server and download new files - by calling it from a Python script that would check the output and re-run the updater as necessary.  I wanted to use the &lt;a href="http://docs.python.org/lib/node528.html"&gt;subprocess module&lt;/a&gt;, as I was advised by the Python docs that this was the New Cool Thing, and I wanted to use the environment variable functionality that it provided.&lt;br /&gt;&lt;br /&gt;However, I consistently received the following error:&lt;br /&gt;&lt;br /&gt;    [20080506 19:05:00] SmartFTP FTP Library v1.5.8.21&lt;br /&gt;    [20080506 19:05:00] Resolving host name "ftp.******.com"&lt;br /&gt;    [20080506 19:05:00] Unable to resolve host name.&lt;br /&gt;    [20080506 19:05:00] 1&lt;br /&gt;&lt;br /&gt;So I replaced the hostname with the IP address and got this error instead:&lt;br /&gt;&lt;br /&gt;    The requested service provider could not be loaded or initialized.&lt;br /&gt;&lt;br /&gt;I found this phrase in the Microsoft Winsock documentation, at which point I had a mild aneurysm and went to work on something else for a while.  I came back a little later to read that documentation, but it was unhelpful. &lt;br /&gt;&lt;br /&gt;Finally I switched over to declaring the environment variables and calling the executable in a batch file and called that using &lt;a href="http://docs.python.org/lib/os-process.html"&gt;os.system&lt;/a&gt; instead of subprocess... and it worked fine.  So it appears that there's some incompatibility between this vendor app and/or SmartFTP's FTP library and Python's subprocess module.  Guess I'll be using the tried and true os.system for now, because it's definitely not worth any more debugging time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-7851817392542086243?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/7851817392542086243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=7851817392542086243' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7851817392542086243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7851817392542086243'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/05/pythons-subprocess-doesnt-like-smartftp.html' title='Python&apos;s subprocess doesn&apos;t like SmartFTP'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-3254697602644826828</id><published>2008-05-02T13:17:00.001-07:00</published><updated>2008-05-02T13:52:11.881-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ftp'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>How to break your FTP client</title><content type='html'>Haven't posted in a while because I was in Russia for a few weeks checking out the smog, vodka, and beautiful women.  Now I'm back, and I have a quick non-database item to relate.&lt;br /&gt;&lt;br /&gt;Today I was working on scheduling the execution of some updater software from a small data vendor of ours.  As it turns out, they have no spec or unified framework for their error handling and messages, so I had to work out what sort of errors could happen on my own.  One thing the updater does is log on to the vendor's server via FTP and download new files.  So naturally I wanted to prevent this to see what would happen.&lt;br /&gt;&lt;br /&gt;The easiest way would have been to just unplug my network connection, but the app needs some files that live on the network, so that was out.&lt;br /&gt;&lt;br /&gt;I tried to block the program with Windows Firewall, but we've got a bunch of Group Policy stuff applied there, which complicated things.  Even when I unchecked my local firewall exception for the app, and then also the exception for FTP, the application connected to the vendor's FTP server without any trouble. &lt;br /&gt;&lt;br /&gt;Next I went out and found a 3rd party app that could block ports.  The one I settled on after a quick browse of some security sites was Ghost Personal Firewall.  Simple, straightforward, free, quick installation - suited my needs perfectly.  And it worked great.  It took 2 minutes to download, install (no reboot needed), and configure a rule to block all traffic on port 21.  This had the desired effect of breaking the app and producing an error log.&lt;br /&gt;&lt;br /&gt;So consider this an unsolicited endorsement of Ghost's firewall.  Served my purpose just fine, and it's going into my security toolkit for future app testing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-3254697602644826828?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/3254697602644826828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=3254697602644826828' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/3254697602644826828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/3254697602644826828'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/05/how-to-break-your-ftp-client.html' title='How to break your FTP client'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1948213249607921020</id><published>2008-03-27T08:07:00.000-07:00</published><updated>2008-03-27T13:00:42.032-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyodbc'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Returning rows from a stored procedure with pyodbc</title><content type='html'>I'll start with the executive summary for those of you short on time or who don't care about the background:&lt;br /&gt;&lt;br /&gt;When executing multiple statements within a SQL Server stored procedure, including a SELECT statement that you expect to return rows to a rowset via pyodbc, it is necessary to SET NOCOUNT ON.&lt;br /&gt;&lt;br /&gt;Backstory:&lt;br /&gt;&lt;br /&gt;I ran into a new issue with pyodbc yesterday - an inability to parse rows returned by a SQL Server stored procedure.  The proc in question was executing a number of queries, generating logging as rows to a table variable, and then returning the log via a select statement against the table variable.&lt;br /&gt;&lt;br /&gt;However, when I executed the statement from a pyodbc connection, it didn't work.&lt;br /&gt;&lt;br /&gt;This was a fairly complex proc that caused changes in the database when executed and I didn't want to run it repeatedly, so I mocked up "spTest" as follows:&lt;br /&gt;&lt;br /&gt;create proc spTest as&lt;br /&gt;select 'a' as msg&lt;br /&gt;union all select 'b'&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt;When executed from Python:&lt;br /&gt;&lt;br /&gt;db = pyodbc.connect(CNXNSTRING, True)&lt;br /&gt;rows = db.execute("exec spTest")&lt;br /&gt;for row in rows:&lt;br /&gt;   print row&lt;br /&gt;&lt;br /&gt;This returned rows.  So I added a table variable:&lt;br /&gt;&lt;br /&gt;create proc spTest2 as&lt;br /&gt;declare @msgs table (msg varchar(255))&lt;br /&gt;&lt;br /&gt;insert into @msgs&lt;br /&gt;select 'a' as msg&lt;br /&gt;union all select 'b'&lt;br /&gt;&lt;br /&gt;select * from @msgs&lt;br /&gt;go&lt;br /&gt;&lt;br /&gt;This, being more similar to the actual proc, did not work.  I changed a few things, tried a temp table instead of a table variable, etc., but didn't get any better results.  Then my esteemed colleague Pijus asked if it was possible that pyodbc was reading some other channel of information from SQL that was obscuring the results.  Aha!&lt;br /&gt;&lt;br /&gt;SQL spits out rowcounts by default.  I'm not sure where these turn up in ODBC world, but I know that they do get provided to the ODBC driver, and that does constitute an additional channel of information that could be confusing pyodbc.  So I SET NOCOUNT ON, and voila, the final select returns results regardless of how many other operations occur within the procedure.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1948213249607921020?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1948213249607921020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1948213249607921020' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1948213249607921020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1948213249607921020'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/03/returning-rows-from-stored-procedure.html' title='Returning rows from a stored procedure with pyodbc'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-3519849725694139294</id><published>2008-03-12T07:28:00.000-07:00</published><updated>2008-03-12T07:36:13.389-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>Case Sensitive GROUP BY</title><content type='html'>This is fairly trivial, but it took a few minutes to work out, so I figured I'd post it.  Someone on my team needed to perform a case-sensitive GROUP BY operation on a table with a case-insensitive collation.  I had performed case-sensitive SELECTs before by "casting" the field in question to an alternate collation, so I tried that, but couldn't get it to work at first.  Of course, had I thought about it, I would have realized that the same operation needs to be applied in both the GROUP BY and the SELECT.&lt;br /&gt;&lt;br /&gt;Ex:&lt;br /&gt;&lt;br /&gt;create table foo&lt;br /&gt;(bar varchar(20))&lt;br /&gt;&lt;br /&gt;insert into foo select 'Banana'&lt;br /&gt;insert into foo select 'banana'&lt;br /&gt;insert into foo select 'Banana'&lt;br /&gt;&lt;br /&gt;select * from foo&lt;br /&gt;&lt;br /&gt;select&lt;br /&gt;   bar COLLATE SQL_Latin1_General_CP1_CS_AS&lt;br /&gt;   , count(*)&lt;br /&gt;from foo&lt;br /&gt;group by bar COLLATE SQL_Latin1_General_CP1_CS_AS&lt;br /&gt;&lt;br /&gt;Alternately, one could use Microsoft's &lt;a href="http://support.microsoft.com/kb/171299"&gt;recommended method&lt;/a&gt; and convert the field to binary and then back.  I haven't performance-tested the two methods, so I'm not sure which is faster.  I leave that as an exercise for the reader.  ;)&lt;br /&gt;&lt;br /&gt;select convert(varchar(20),x.bar), x.ct&lt;br /&gt;from&lt;br /&gt;   (select&lt;br /&gt;       convert(binary(20), bar) as bar&lt;br /&gt;       , count(*) as ct&lt;br /&gt;   from foo&lt;br /&gt;   group by convert(binary(20),bar)&lt;br /&gt;   ) as x&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-3519849725694139294?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/3519849725694139294/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=3519849725694139294' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/3519849725694139294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/3519849725694139294'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/03/case-sensitive-group-by.html' title='Case Sensitive GROUP BY'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2986146953510424742</id><published>2008-03-10T12:31:00.000-07:00</published><updated>2008-03-10T12:35:40.671-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyodbc'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>INSERT problems via pyodbc</title><content type='html'>This is really stupid, but I just wasted about an hour of dev time trying to figure out why my INSERT statements weren't working from a Python script using pyodbc even though SELECTs were fine.  As it turns out, they were getting rolled back because I wasn't explicitly committing the transactions and hadn't set the AUTOCOMMIT option to true for the connection.&lt;br /&gt;&lt;br /&gt;So if you happen to search for "pyodbc INSERT problems" (as I did), hopefully you'll stumble across this (as opposed to nothing, which is what I found) and slap yourself in the head (as I did).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2986146953510424742?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2986146953510424742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2986146953510424742' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2986146953510424742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2986146953510424742'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/03/insert-problems-via-pyodbc.html' title='INSERT problems via pyodbc'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2865588292684319088</id><published>2008-03-10T08:22:00.000-07:00</published><updated>2008-03-10T09:02:48.658-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><category scheme='http://www.blogger.com/atom/ns#' term='CLR'/><title type='text'>SQL Server CLR Remote Debugging</title><content type='html'>My CLR stored procs have matured to the point that they're being deployed, which is to say that the bugs are now insidious rather than blatant.  It's a royal pain to make changes, deploy the project locally, run the post-deploy correction script to fix the decimal precision on everything (see &lt;a href="http://nyc-dba.blogspot.com/2008/02/sqldecimal-truncation-oddity.html"&gt;previous post&lt;/a&gt;), debug any issues, and then do the whole deployment again to the dev server.  It's much easier to just debug it straight on the server.&lt;br /&gt;&lt;br /&gt;Fortunately, remote debugging is a straightforward process.  Predictably, Microsoft's docs (here's &lt;a href="http://msdn2.microsoft.com/en-us/library/s0fk6z6e%28VS.80%29.aspx"&gt;one&lt;/a&gt; of many) on the subject are somewhat convoluted, although this msdn &lt;a href="http://blogs.msdn.com/sqlclr/archive/2006/06/29/651644.aspx"&gt;blog post&lt;/a&gt; helped.&lt;br /&gt;&lt;br /&gt;All you really need to do is install Remote Debugging Monitor on the server and run it under the same login you use to connect to SQL.  It comes with its own standalone installer on the Visual Studio CD, just look for the Remote Debugger directory and run the setup app found there.  Then you can run it either manually or as a service.&lt;br /&gt;&lt;br /&gt;Next, place a breakpoint in your code somewhere and deploy it to the server.  I've had trouble with my test scripts when deploying/debugging all at once - basically, they hang without ever running - so what I've started doing is this:&lt;br /&gt;&lt;br /&gt;1) Start without debugging (Ctrl-F5) to deploy to the remote server&lt;br /&gt;2) Run my decimal parameter correction script&lt;br /&gt;3) Attach to Process in Visual Studio to sqlservr.exe on the remote server&lt;br /&gt;4) Execute the proc or UDF in a SQL Management Studio window&lt;br /&gt;&lt;br /&gt;Then I can step through the code, look at locals, and generally debug to my heart's content.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2865588292684319088?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2865588292684319088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2865588292684319088' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2865588292684319088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2865588292684319088'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/03/sql-server-clr-remote-debugging.html' title='SQL Server CLR Remote Debugging'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8064714275392353144</id><published>2008-02-22T09:22:00.001-08:00</published><updated>2008-04-01T09:42:44.231-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='UDF'/><category scheme='http://www.blogger.com/atom/ns#' term='CLR'/><title type='text'>SqlDecimal truncation oddity</title><content type='html'>I've been working with all sorts of SQL CLR integration lately - User Defined Types (which are a bad idea), stored procs, and UDFs. In general, I'm pretty happy with the stored procedures, although I've run up against a number of irritating (but understandable) limitations, like the inability to dynamically load libraries and the requirement that only SQL data types be passed in and out of the CLR stored procs. But I haven't really broken any new ground, so I haven't written about it.&lt;br /&gt;&lt;br /&gt;Today's issue is also not ground-breaking, but it is odd, so I thought I'd mention it. I wrote a function to convert a date into a decimal. Better that you not ask why. Here's the code:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;public partial class UserDefinedFunctions&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    [Microsoft.SqlServer.Server.SqlFunction]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    public static SqlDouble fnTimeSeriesCalcFracYrFromDateS(SqlDateTime inputDT)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        DateTime dt = (DateTime)inputDT;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        double temp = (dt.Year + (Math.Round(((double)dt.Month * (365 / 12) + (double)dt.Day) * 1000000 / 365) / 1000000));&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        SqlDecimal temp2 = (SqlDecimal)temp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        return temp2;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Obviously I could have dispensed with almost all of that by casting the data types within a single line, but I broke it out for debugging purposes.&lt;br /&gt;&lt;br /&gt;Here's the funny part: when placing a breakpoint at the return statement, here are the values of the variables:&lt;br /&gt;&lt;br /&gt;inputDT {1/2/2008 12:00:00 AM} System.Data.SqlTypes.SqlDateTime&lt;br /&gt;dt {1/2/2008 12:00:00 AM} System.DateTime&lt;br /&gt;temp 2008.087671 double&lt;br /&gt;temp2 {2008.0876710000000} System.Data.SqlTypes.SqlDecimal&lt;br /&gt;&lt;br /&gt;All as they should be. But the output of the function is 2008.&lt;br /&gt;&lt;br /&gt;Why? I have no idea. I'm guessing it has something to do with the SqlDecimal declaration of the function, because when I changed it to SqlDouble, it returns 2008.087671 as it should. Anybody know why this is happening?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;UPDATE:&lt;/span&gt; Figured it out. Visual Studio deploys the UDF without specifying a precision and scale, which causes the scale to be set to 0.  One can circumvent this by dropping and re-creating the function manually within SQL Server and declaring the decimal data type with the desired precision and scale (in this case, (10,6)).&lt;br /&gt;&lt;br /&gt;However, this is annoying because it turns a one-button deploy/debug process into a multi-step process, since one can't use the test script functionality in Visual Studio to run a script with multiple "GOs" to drop and re-create the function and then run it.  The workaround I devised was to&lt;br /&gt;&lt;br /&gt;1) Deploy the function to SQL via Visual Studio.&lt;br /&gt;2) Drop and re-create the function manually in SQL Management Studio.&lt;br /&gt;3) Set a breakpoint in VS.&lt;br /&gt;4) Attach VS to the sqlservr.exe process.&lt;br /&gt;5) Run the function.  It should hit the breakpoint, allowing you to debug when it has the correct variable type settings.&lt;br /&gt;&lt;br /&gt;But it would be nice to get back to where one press of F5 deployed and debugged the whole thing.  Maybe I can figure out a way to set up a custom deploy script from VS...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;UPDATE 2: &lt;/span&gt;When attempting to deploy the CLR functions after manually dropping them and re-creating them with the desired precision on the decimal return types, you get a Deploy error like the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;The assembly module 'fnTimeSeriesCalcFracYrFromDateS' cannot be re-deployed because it was created outside of Visual Studio.  Drop the module from the database before deploying the assembly.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To get around this, you can write a SQL script to drop the functions if they exist, save it into your project directory, and use the Pre-build event command line on the Build Events tab of the project properties to execute that drop script before each deploy.  One less step per build!&lt;br /&gt;&lt;br /&gt;Next I have to figure out how to get the post-build to execute the script to drop and recreate the functions with the proper precision.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8064714275392353144?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8064714275392353144/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8064714275392353144' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8064714275392353144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8064714275392353144'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/02/sqldecimal-truncation-oddity.html' title='SqlDecimal truncation oddity'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-998068043580675389</id><published>2008-01-28T13:50:00.000-08:00</published><updated>2008-01-28T14:09:02.592-08:00</updated><title type='text'>Arggh</title><content type='html'>I wrote this nice little piece of code to eliminate tons of redundant rows from a 70-million row table, tested it in a vacuum in Dev, put it in the Integration environment for 3 weeks... and had it blow up spectacularly when applied to Production this weekend because of triggers on the table that I hadn't accounted for.  Stupid legacy code!&lt;br /&gt;&lt;br /&gt;There's no real content to this story, I'm just venting.  The only moral is TEST YOUR CODE.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-998068043580675389?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/998068043580675389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=998068043580675389' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/998068043580675389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/998068043580675389'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2008/01/arggh.html' title='Arggh'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1362498619916522228</id><published>2007-12-11T13:51:00.000-08:00</published><updated>2007-12-11T14:43:35.456-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DENSE_RANK'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='RANK'/><title type='text'>More fun with ranking functions</title><content type='html'>I don't think I really understood why Mike F at Capital IQ was so excited about the SQL 2005 ranking functions until just recently, but I'm using them all over the place now. Minutes after kicking off the time series load I described in my last post, I came across another use for RANK.&lt;br /&gt;&lt;br /&gt;EDIT: As I review this, I recognize that this is pretty esoteric and may not have much practical application for most people.  You've been warned.&lt;br /&gt;&lt;br /&gt;Like many financial companies, we get data from multiple vendors, and we have to decide which vendor's data to use in each case.  So I've got a set of data provided by multiple Vendors, grouped by ObjectId and Date, that is ranked for each date by some business logic built into the procedure that loads the data. The best (lowest, in this case) ranked row for each ObjectId and Date gets a bit flag set; we'll call it IsBest.&lt;br /&gt;&lt;br /&gt;However, it was uncovered that there was an extra negation in the business logic for many cases, so many of the rows had the bit flag set incorrectly.  I needed to find a way to determine what portion of the data had the flag set incorrectly.  This could be accomplished using any  number of data warehousing techniques - Analysis Services is well-suited to it, for example, or Microstrategy, or even a complicated series of GROUP BYs.  But I didn't want to go to all that trouble just to produce a single ad hoc report, so I found another way.&lt;br /&gt;&lt;br /&gt;Some (totally made up, to prevent my employer from having me whacked) sample data, in which only objectId 4 has the correct settings for the bit flag:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_8yUEHkyTv1w/R18P-NZit9I/AAAAAAAAAQ8/p39MgobTStc/s1600-h/IsBestBadData.png"&gt;&lt;img style="cursor: pointer;" src="http://bp3.blogger.com/_8yUEHkyTv1w/R18P-NZit9I/AAAAAAAAAQ8/p39MgobTStc/s400/IsBestBadData.png" alt="" id="BLOGGER_PHOTO_ID_5142846860903495634" border="0" /&gt;&lt;/a&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;I needed to find rows in which the highest-ranked VendorId had the IsBest flag set for a given ObjectId and Date, and any rows in which a lower-ranked VendorId did not have the IsBest flag set.   Any other combination is incorrect.  If I'm only worried about how many rows need to be fixed, I can stop there, or I can divide the sum of those two rowcounts by the total number of rows to get a percentage of data that is correct.&lt;br /&gt;&lt;br /&gt;A query to return the rowcounts follows.  I'm using DENSE_RANK rather than RANK to keep the ranking correct despite duplicate rows (as in objectId 3).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SELECT&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   IsBest, DRank, count(*)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;FROM&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;(SELECT&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   [Date]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   , ObjectId&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   , VendorId&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   , IsBest&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   , DENSE_RANK() OVER (PARTITION BY Date, ObjectId ORDER BY Priority) as DRank&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;from tbSource&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;) as allRows&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;group by IsBest, DRank&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;order by IsBest, DRank&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Additional code could be added to this query to automatically sum the correct cases and determine the percentages, but I will leave that as an exercise for the reader.  Here are the raw counts, with the correct cases highlighted:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_8yUEHkyTv1w/R18SUtZit-I/AAAAAAAAARE/gUtM2d8ATFs/s1600-h/IsBestCounts.png"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_8yUEHkyTv1w/R18SUtZit-I/AAAAAAAAARE/gUtM2d8ATFs/s400/IsBestCounts.png" alt="" id="BLOGGER_PHOTO_ID_5142849446473807842" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1362498619916522228?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1362498619916522228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1362498619916522228' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1362498619916522228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1362498619916522228'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/12/more-fun-with-ranking-functions.html' title='More fun with ranking functions'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp3.blogger.com/_8yUEHkyTv1w/R18P-NZit9I/AAAAAAAAAQ8/p39MgobTStc/s72-c/IsBestBadData.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-4526970665038974906</id><published>2007-12-11T11:58:00.000-08:00</published><updated>2007-12-11T13:22:22.430-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='RANK'/><title type='text'>Another cool use for RANK() - Time Series</title><content type='html'>I've got a big set of time series data across many object instances that needs to be inserted into a table that uses a trigger to set the "End Time" of each segment in the series.  In other words, data like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_8yUEHkyTv1w/R17xhdZit6I/AAAAAAAAAQk/9C9INmSOGzo/s1600-h/TimeSeriesRawData.png"&gt;&lt;img style="cursor: pointer;" src="http://bp3.blogger.com/_8yUEHkyTv1w/R17xhdZit6I/AAAAAAAAAQk/9C9INmSOGzo/s400/TimeSeriesRawData.png" alt="" id="BLOGGER_PHOTO_ID_5142813381633423266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;When a new row for a given ObjectId is inserted, the previous row in the series is given an EndTime equal to the StartTime for the new row.  Usually, this is done one row at a time, with only one row coming into the table for each ObjectId at a time.&lt;br /&gt;&lt;br /&gt;However, in this case, I need to backfill a lot of data, which will cause the trigger to not behave as expected.  I have a few options to work around this:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Insert each row one at a time.  Turns out there are over a million rows to be inserted and this is a heavily-used table, so this option is undesirable.&lt;/li&gt;&lt;li&gt;Write a script to generate the EndTimes for each row ahead of time.  This could be tricky and CPU-intensive, and I'd rather avoid it if possible.&lt;/li&gt;&lt;li&gt;Partition the data such that the trigger will work as it's supposed to, but large batches of data can be inserted instead of inserting one row at a time.&lt;/li&gt;&lt;/ol&gt;I'm currently investigating option 3, especially because it lets me use the RANK() function.  The basic idea is this: for each ObjectId, rank the StartTimes, then loop through and insert all rows where RANK = 1, then 2, 3, etc.  This will insert all the ObjectIds with their initial StartTime, then the next StartTime, and so on, allowing the trigger to fire on each round and update the EndTimes en masse.&lt;br /&gt;&lt;br /&gt;The query I'm using (generalized for mass consumption):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;INSERT INTO tbTemp&lt;br /&gt;SELECT&lt;br /&gt;   ObjectId&lt;br /&gt;   , Value&lt;br /&gt;   , StartTime&lt;br /&gt;   , RANK() OVER (PARTITION BY ObjectId ORDER BY StartTime) as Ord&lt;br /&gt;FROM&lt;br /&gt;   tbSource&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Then the data in tbTemp can be looped through by rank and inserted into the destination table.&lt;br /&gt;&lt;br /&gt;And the resulting data should look like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_8yUEHkyTv1w/R172sNZit7I/AAAAAAAAAQs/ABuu3g7ggP4/s1600-h/TimeSeriesDataPostTrigger.png"&gt;&lt;img style="cursor: pointer;" src="http://bp2.blogger.com/_8yUEHkyTv1w/R172sNZit7I/AAAAAAAAAQs/ABuu3g7ggP4/s400/TimeSeriesDataPostTrigger.png" alt="" id="BLOGGER_PHOTO_ID_5142819063875155890" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-4526970665038974906?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/4526970665038974906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=4526970665038974906' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4526970665038974906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4526970665038974906'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/12/another-cool-use-for-rank-time-series.html' title='Another cool use for RANK() - Time Series'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp3.blogger.com/_8yUEHkyTv1w/R17xhdZit6I/AAAAAAAAAQk/9C9INmSOGzo/s72-c/TimeSeriesRawData.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5061129440481699893</id><published>2007-11-29T12:10:00.000-08:00</published><updated>2007-11-29T12:32:09.099-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='indexing'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='physical database design'/><title type='text'>Many-to-many physical table design</title><content type='html'>I was creating a new set of tables (we'll say 2 for simplicity) that will contain rows that can have many-to-many relationships, and I was pondering how best to design the association table so as to optimize IO.&lt;br /&gt;&lt;br /&gt;In this table scenario, joins can come from either direction, so it could be one row from the first table that joins to many in the second, or vice versa.  I'm generally a big fan of a clustered index on some column, especially an integer ID if it's useful, but in this case, I think the best performance would be achieved by dispensing with the clustered index and ID column altogether.  The basic table design would be as follows:&lt;br /&gt;&lt;br /&gt;CREATE TABLE User&lt;br /&gt;(&lt;br /&gt;UserId INT IDENTITY(1,1)&lt;br /&gt;, ...&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;CREATE TABLE Group&lt;br /&gt;(&lt;br /&gt;GroupId INT IDENTITY(1,1)&lt;br /&gt;, ...&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;CREATE TABLE UserToGroup&lt;br /&gt;(&lt;br /&gt;UserId INT&lt;br /&gt;, GroupId INT&lt;br /&gt;, ?&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;A clustered index on UserId would speed up queries starting with a User and joining to Groups, but it would fragment as old users added groups, splitting pages to insert UserIds.  The reverse would be true of clustering on GroupId.  Unless the query pattern supported such an unbalanced design which would require frequent index defragmentation, either of these clustered indices would be less than ideal.&lt;br /&gt;&lt;br /&gt;Adding a surrogate key identity column would be no better; it would prevent index fragmentation, but the index wouldn't be used for seeks, and the column would add 50% more space on disk between the columns that we really care about, making I/O proportionately slower.&lt;br /&gt;&lt;br /&gt;The best design should be a heap, with nonclustered indices on UserId, GroupId and GroupId, UserId.  Or more specifically, in SQL Server 2005, indices on UserId and GroupId, with the other column set up as an "included column" to make each index covering. &lt;br /&gt;&lt;br /&gt;I haven't tested this yet, though, so I welcome any comments or contradictions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5061129440481699893?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5061129440481699893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5061129440481699893' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5061129440481699893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5061129440481699893'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/11/many-to-many-physical-table-design.html' title='Many-to-many physical table design'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-3109010461109117225</id><published>2007-11-27T14:50:00.000-08:00</published><updated>2007-11-27T14:58:48.274-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSIS'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><title type='text'>Odd SSIS bug</title><content type='html'>Here's what happened: I added a column to a source table, went into the Data Flow source, refreshed the table list, selected the table, and checked all the output columns that I wanted.  Then I resolved all the naming issues with the downstream tasks.&lt;br /&gt;&lt;br /&gt;But I'm getting an error (#1 below) when I try to build, because for some reason SSIS will not automatically add the new column to the Error Output, and it won't let me add a column to that output, even in the Advanced Editor.  This is annoying.  I'm probably going to need to delete and add this data source, which is going to screw up all my transformations.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Error Message #1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Error at Data Flow Task [tbCA Source [1]]: The output column "CaxSubTypeId" (1052) on the non-error output has no corresponding output column on the error output.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Error Message #2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;TITLE: Microsoft Visual Studio&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt; ------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt; Error at Data Flow Task [tbCA Source [1]]: The component does not allow adding columns to this input or output.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-3109010461109117225?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/3109010461109117225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=3109010461109117225' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/3109010461109117225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/3109010461109117225'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/11/odd-ssis-bug.html' title='Odd SSIS bug'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1681158639097888949</id><published>2007-10-09T10:09:00.001-07:00</published><updated>2007-10-09T10:13:28.245-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='off topic'/><title type='text'>off topic again</title><content type='html'>While catching up on the thousands of RSS articles that showed up in Google Reader while I was on vacation for a week, I read Scott Hanselman's &lt;a href="http://www.hanselman.com/blog/TypingTestTwiceOnceWithVoiceRecognition.aspx"&gt;post&lt;/a&gt; about typing speed and speech recognition and immediately had to take the &lt;a href="http://www.typequick.com/ttest/testyourskills.html"&gt;test&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Number of words typed: 261&lt;br /&gt;Test duration: 3 min&lt;br /&gt;Speed: 87.0 words/min. (435 keystrokes/min.)&lt;br /&gt;Error penalty: 10&lt;br /&gt;Accuracy: 96.2%&lt;br /&gt;&lt;br /&gt;Ha!  I win!  (He managed 72.6)&lt;br /&gt;&lt;br /&gt;Actually, I'm surprised I managed 87 wpm, but I have to admit, this test was slightly stressful.  I was trying hard.  I probably average around 60 most of the time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1681158639097888949?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1681158639097888949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1681158639097888949' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1681158639097888949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1681158639097888949'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/10/off-topic-again.html' title='off topic again'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1224205602597490580</id><published>2007-09-20T09:17:00.000-07:00</published><updated>2007-09-25T13:49:00.971-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2000'/><category scheme='http://www.blogger.com/atom/ns#' term='regular expressions'/><category scheme='http://www.blogger.com/atom/ns#' term='dts'/><title type='text'>Regex for linked servers</title><content type='html'>As part of the DTS migration I mentioned in my last post, I wrote a few functions to find less-than-ideal code. One thing we wanted to get rid of was linked-server joins, and the easiest way to find those was to check each Execute SQL task using a regular expression (long live &lt;a href="http://tools.osherove.com/"&gt;Regulazy&lt;/a&gt;). So once again I'm using this blog as my personal source repository and re-producing the regex for this.&lt;br /&gt;&lt;br /&gt;Regex for linked server queries:&lt;br /&gt;&lt;strong&gt;(\S+)\.(\S+)\.dbo\.(\S+)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I tried to generate an expression to find "SELECT...INTO" where ... did not contain @ or FROM, but couldn't figure it out with the meager regex capabilities of VBScript. Seems like a lookahead or lookbehind would probably work for this purpose, but according to the &lt;a href="http://aspnet.4guysfromrolla.com/articles/022603-1.aspx"&gt;4 Guys From Rolla&lt;/a&gt;, VBScript regex does not support these.&lt;br /&gt;&lt;br /&gt;UPDATE: Spent a little more time on it and figured out a suitable regular expression to find instances of SELECT INTO that excludes INSERT INTO and SELECT FROM.&lt;br /&gt;&lt;br /&gt;Regex for SELECT INTO:&lt;br /&gt;&lt;strong&gt;select((?!from)(?!insert).\n)*into&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;UPDATE 2: My first SELECT INTO regex was foiled by something like "SELECT foo, bar, admintool from ...", so I fixed it to make sure there's whitespace before and after the SELECT and the INTO.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;select[\s]((?!from)(?!insert).\n)*[\s]into[\s]&lt;/strong&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1224205602597490580?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1224205602597490580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1224205602597490580' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1224205602597490580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1224205602597490580'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/09/regex-for-linked-servers.html' title='Regex for linked servers'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5192117158904914572</id><published>2007-09-11T12:37:00.000-07:00</published><updated>2007-09-11T14:01:49.964-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2000'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='dts'/><title type='text'>Parsing the filesystem for files</title><content type='html'>I'm sure this has been done many times before, but this is my implementation. I needed it to run a large DTS migration from files stored on disk, so first I needed a list of those files. They were contained in a directory tree in no particular order, and in many levels of subdirectories. I wanted a generalized solution to the parsing, so here it is.&lt;br /&gt;&lt;br /&gt;Pasting it into Blogger butchered my formatting, but it feels like a waste of time to fix it, since it will probably not paste properly back into an editor anyway. I made the (minimal) comments green just to break it up a bit.&lt;br /&gt;&lt;br /&gt;As usual, no warranty or even functionality of this code is expressed or implied. Use at your own risk, especially since I'm not sure the xp_subdirs extended proc is supported and xp_cmdshell can definitely be dangerous.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:78%;"&gt;&lt;span style="color:#33cc00;"&gt;/*************************************************&lt;br /&gt;** get list of dirs to search for files&lt;br /&gt;*************************************************/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;declare @currentdir varchar(1000)&lt;br /&gt;declare @fullpath varchar(1000)&lt;br /&gt;declare @basepath varchar(1000)&lt;br /&gt;&lt;br /&gt;set @basepath = 'c:\stuff'&lt;br /&gt;set @fullpath = @basepath&lt;br /&gt;&lt;br /&gt;if exists (select 1 from tempdb.dbo.sysobjects where name like '#dirs___%')&lt;br /&gt;drop table #dirs&lt;br /&gt;&lt;br /&gt;create table #dirs&lt;br /&gt;(&lt;br /&gt;directory varchar(1000)&lt;br /&gt;, done bit&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;if exists (select 1 from tempdb.dbo.sysobjects where name like '#dirtemp___%')&lt;br /&gt;drop table #dirtemp&lt;br /&gt;&lt;br /&gt;create table #dirtemp&lt;br /&gt;( directory varchar(1000) )&lt;br /&gt;&lt;br /&gt;insert into #dirtemp exec master.dbo.xp_subdirs @fullpath&lt;br /&gt;&lt;br /&gt;insert into #dirs&lt;br /&gt;select&lt;br /&gt;'\' + directory as directory&lt;br /&gt;, 0 as done&lt;br /&gt;from #dirtemp&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Loop: &lt;span style="color:#33cc00;"&gt;-- xp_subdirs spits out errors when a dir has no subdirs, so they have to be caught with this GOTO Loop construct&lt;br /&gt;&lt;/span&gt;while exists (select 1 from #dirs where done = 0)&lt;br /&gt;begin&lt;br /&gt;if exists (select 1 from tempdb.dbo.sysobjects where name like '#subdirs___%')&lt;br /&gt;drop table #subdirs&lt;br /&gt;&lt;br /&gt;create table #subdirs&lt;br /&gt;( directory varchar(255) )&lt;br /&gt;&lt;br /&gt;select top 1 @currentdir = directory from #dirs where done = 0&lt;br /&gt;&lt;br /&gt;set @fullpath = @basepath + @currentdir&lt;br /&gt;&lt;br /&gt;exec master.dbo.xp_subdirs @fullpath&lt;br /&gt;if (@@ERROR &lt;&gt; 0)&lt;br /&gt;begin&lt;br /&gt;update #dirs set done = 1 where @currentdir = directory&lt;br /&gt;GOTO Loop&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;insert into #subdirs exec master.dbo.xp_subdirs @fullpath&lt;br /&gt;insert into #dirs select @currentdir + '\' + s.directory, 0 as done from #subdirs s&lt;br /&gt;update #dirs set done = 1 where @currentdir = directory&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;if exists (select 1 from tempdb.dbo.sysobjects where name like '#dirtemp___%')&lt;br /&gt;drop table #dirtemp&lt;br /&gt;&lt;br /&gt;if exists (select 1 from tempdb.dbo.sysobjects where name like '#subdirs___%')&lt;br /&gt;drop table #subdirs&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#33cc00;"&gt;/*************************************************&lt;br /&gt;** get list of files&lt;br /&gt;*************************************************/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;declare @command varchar(1000)&lt;br /&gt;declare @fileextension varchar(5)&lt;br /&gt;&lt;br /&gt;set @fileextension = 'dts'&lt;br /&gt;&lt;br /&gt;if exists (select 1 from tempdb.dbo.sysobjects where name like '#files___%')&lt;br /&gt;drop table #files&lt;br /&gt;&lt;br /&gt;create table #files&lt;br /&gt;(&lt;br /&gt;filepath varchar(1000)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;update #dirs set done = 0&lt;br /&gt;&lt;br /&gt;while exists (select 1 from #dirs where done = 0)&lt;br /&gt;begin&lt;br /&gt;if exists (select 1 from tempdb.dbo.sysobjects where name like '#filetemp___%')&lt;br /&gt;drop table #filetemp&lt;br /&gt;&lt;br /&gt;create table #filetemp&lt;br /&gt;(&lt;br /&gt;filepath varchar(1000)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;select top 1 @currentdir = directory from #dirs where done = 0&lt;br /&gt;&lt;br /&gt;set @command = 'dir ' + @basepath + @currentdir + '\*.' + @fileextension + ' /B'&lt;br /&gt;&lt;br /&gt;insert into #filetemp exec master.dbo.xp_cmdshell @command&lt;br /&gt;&lt;br /&gt;insert into #files select @basepath + @currentdir + '\' + filepath from #filetemp&lt;br /&gt;&lt;br /&gt;update #dirs set done = 1 where directory = @currentdir&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;if exists (select 1 from tempdb.dbo.sysobjects where name like '#filetemp___%')&lt;br /&gt;drop table #filetemp&lt;br /&gt;&lt;br /&gt;delete from #files where ISNULL(filepath, 'x') not like '%' + @fileextension + '%'&lt;br /&gt;&lt;br /&gt;select * from #files&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5192117158904914572?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5192117158904914572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5192117158904914572' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5192117158904914572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5192117158904914572'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/09/parsing-filesystem-for-files.html' title='Parsing the filesystem for files'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-7807114111433683649</id><published>2007-08-29T06:56:00.000-07:00</published><updated>2007-08-29T06:58:34.346-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='russia'/><title type='text'>Completely off-topic</title><content type='html'>My globe-trotting brother has started a blog.  He's currently hanging out in Moscow doing translation work for a big Russian firm, and while I'm not sure what the typical content will be like, he's a good writer, so it should be interesting.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://russiatranslated.blogspot.com/"&gt;http://russiatranslated.blogspot.com/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-7807114111433683649?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/7807114111433683649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=7807114111433683649' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7807114111433683649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7807114111433683649'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/08/completely-off-topic.html' title='Completely off-topic'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-9108769552662359616</id><published>2007-08-28T06:29:00.000-07:00</published><updated>2007-09-11T14:02:55.669-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server 2005'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Management Studio'/><title type='text'>SQL Management Studio Setup</title><content type='html'>First off, I'm back at a desk after an excellent time in Europe - a whirlwind tour through Budapest, Bratislava, Krakow, and Vienna. I may have to move to Vienna one of these days, and I will definitely be seeking a trophy wife in Bratislava. So today is my second day at my new employer, an entity I have been informed prefers not to be named publically, so all references to it from here out will be oblique, or possibly substituted with "The Black Chamber."&lt;br /&gt;&lt;br /&gt;In any case, I needed to start setting up my new desktop (that was already built when I got here, by the way, and with three (!) 19" monitors mounted on extremely solid articulating arms), and realized that I can never remember the miscellaneous settings I change in SMS to get it set up the way I like for maximum productivity. Generally I just stumble into them after I try to do something the way I usually do and it doesn't work. So like many other posts on this blog, this is purely for my reference purposes, and if it helps anyone else out, even better.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;ProFont&lt;/strong&gt; - Mike Forman introduced me to this, and I find it absolutely essential these days. I use it as my main text editing and printing font, at 9 point, and it's clearer and smaller at that font size than anything else I've found. I'll make it available for download as soon as I manage to get access to my own FTP server again. Until then, I'm sure it can be googled.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Environment-&gt;Keyboard&lt;/strong&gt; - I add the following:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Ctrl+F1: sp_helptext&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ctrl+3: sp_who2&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ctrl+4: sp_spaceused&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Text Editor-&gt;Plaintext&lt;/strong&gt; - I change the tab spacing to 2. Just my personal preference.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Query Results-&gt;SQL Server-&gt;Results to Grid&lt;/strong&gt; - I check "Display results in a separate tab" and "Switch to results tab after the query executes." I prefer having as much screen real estate as possible for both query and results, and I find it quick to switch between tabs with F6.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;The Change Connection button&lt;/strong&gt; - Another one from Mike, I use the Customize menu option to display the Change Connection icon as Image and Text, and change the Name from "C&amp;hange Connection..." to "Chan&amp;amp;ge Connection...". This allows quick switching of the connection via the keyboard shortcut of Alt-G. The default name needs to be changed because Alt-H brings up the Help menu.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I know there are a few others, but I can't recall them at the moment.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-9108769552662359616?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/9108769552662359616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=9108769552662359616' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/9108769552662359616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/9108769552662359616'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/08/sql-management-studio-setup.html' title='SQL Management Studio Setup'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1473916969877440062</id><published>2007-08-07T07:53:00.000-07:00</published><updated>2008-09-25T09:21:26.117-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>Change of Scenery</title><content type='html'>It's about that time again.  The Big Corporation atmosphere wasn't turning out to be what I wanted, so I'm going small again, moving to [redacted], a hedge fund based in Dallas.  I'll be in the New York office, where I'll be working with some very bright people, who will hopefully point out to me how little I know about SQL, databases, and computer science in general, and then help to further my education in these subjects.&lt;br /&gt;&lt;br /&gt;I have no idea what the rules are regarding any further disclosure about my current and future employers, so that's all I'm going to say for now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1473916969877440062?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1473916969877440062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1473916969877440062' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1473916969877440062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1473916969877440062'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/08/change-of-scenery.html' title='Change of Scenery'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-737042321494200870</id><published>2007-06-25T12:04:00.001-07:00</published><updated>2007-06-25T12:57:19.301-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>Precision</title><content type='html'>There's probably a better way to do this, but this is what occurred to me:&lt;br /&gt;&lt;br /&gt;select&lt;br /&gt;    max(&lt;br /&gt;        len(&lt;br /&gt;            rtrim(&lt;br /&gt;                replace(&lt;br /&gt;                    substring(&lt;br /&gt;                        cast(position as varchar(50))&lt;br /&gt;                        , charindex(&lt;br /&gt;                            '.'&lt;br /&gt;                            , cast(position as varchar(50)))&lt;br /&gt;                        , 50)&lt;br /&gt;                    , '0', '')&lt;br /&gt;                )&lt;br /&gt;            )&lt;br /&gt;        )&lt;br /&gt;from ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-737042321494200870?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/737042321494200870/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=737042321494200870' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/737042321494200870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/737042321494200870'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/06/precision.html' title='Precision'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-7411792157467443946</id><published>2007-06-05T15:00:00.000-07:00</published><updated>2007-06-05T15:01:33.236-07:00</updated><title type='text'>Sprawl</title><content type='html'>Just looked at a refreshed copy of our server list, and we have more servers than users.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-7411792157467443946?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/7411792157467443946/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=7411792157467443946' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7411792157467443946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7411792157467443946'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/06/sprawl.html' title='Sprawl'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1360124690873237524</id><published>2007-05-21T07:36:00.000-07:00</published><updated>2007-05-21T07:58:30.037-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>Standardize!</title><content type='html'>I was trying to restore a database backup from one server onto another this morning, and despite the two having the same drive letters for data and logs, I ran into problems because the directory names were different.  For a company that runs everything based on rules and standards to the point of excess, this is silly.  So I'm making a quick list of SQL Server-related settings that I feel should be standardized across all servers in one's environment.  It just makes things easier!&lt;br /&gt;&lt;br /&gt;1) Directory structures&lt;br /&gt;2) Default data and log locations&lt;br /&gt;3) Drive letters, if possible&lt;br /&gt;4) Build levels (Service Pack/hotfix)&lt;br /&gt;5) Logins, although these may be different between Dev, QA, and Prod&lt;br /&gt;6) Install locations - I have never found a valid reason to install SQL Server on the C: drive of a non-desktop, but I keep seeing it&lt;br /&gt;&lt;br /&gt;I'm sure I'll add to this list as I come up with more obnoxiously un-standardized settings in our environment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1360124690873237524?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1360124690873237524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1360124690873237524' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1360124690873237524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1360124690873237524'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/05/standardize.html' title='Standardize!'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8325546555304629413</id><published>2007-05-16T12:50:00.000-07:00</published><updated>2007-05-16T13:10:03.242-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='SAN'/><title type='text'>WRITELOG waits</title><content type='html'>My team has been assisting another team off and on for several months with performance tuning their overnight DB processes.  There are many possible bottlenecks in their process, but since the app writing into the DB is highly complex and multi-tiered, we're trying to focus on the internal DB issues first.  &lt;br /&gt;&lt;br /&gt;The first big win was dropping triggers from the tables being written to, which resulted in a 20% reduction in overall job time.  Now the biggest WAITTYPE during the process is WRITELOG, with about 50-60% of the overall time in both QA and Prod.  NETWORKIO is next, and I'd really like to SET NOCOUNT ON, since these writes are created as individual transactions and dropping the count should reduce the NETWORKIO substantially, but that's been problematic so far.&lt;br /&gt;&lt;br /&gt;Digging into the WRITELOG waits, the disk queues are pretty low (0-5 range going against 80 or so physical disks on a big Hitachi SAN with a ton of cache), so the storage guys have dismissed the disk as the problem.  However, I think it's still the disk, just not in the usual way.&lt;br /&gt;&lt;br /&gt;The standard problem is that the disk subsystem runs out of write cache and has to start de-staging data to disk, and the physical disks can't write data as fast as it's coming in.  That's not the case here, because the cache on the SAN is huge (70+ GB, according to the SAN guys), it can accept data faster than the logs are created, and it hasn't gotten close to the high watermark, when it starts de-staging.  So what's the problem?&lt;br /&gt;&lt;br /&gt;Well, in this case, the disks attached to the SQL Server have been attached as a single logical drive, so all the IOs get queued by Windows against that drive.  Therein lies the problem, I believe.  The SAN is fast, but every operation goes against that same queue, so one slow read for a piece of data not in the cache can slow down all the writelog IOs queued up behind it.  This is what I believe is creating the WRITELOG waits.  &lt;br /&gt;&lt;br /&gt;The proposed solution is simple: add another logical drive dedicated to logs.  Even if it's hitting the same physical disks, the addition of another disk queue should allow the log IOs to flow through without being blocked by slower data IOs or data reads.  Stay tuned to see if it works.&lt;br /&gt;&lt;br /&gt;Addendum: We tried this before at Capital IQ, splitting up sets of disks into multiple metaLUNs and comparing them against the same number of disks in one metaLUN and showed barely any performance gain (within the margin of measurement error).  However, the difference between that situation and this one was the amount of cache involved - we were always past cache on the CapIQ SAN, so the disks were the bottleneck.  Here I suspect it's the queue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8325546555304629413?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8325546555304629413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8325546555304629413' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8325546555304629413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8325546555304629413'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/05/writelog-waits.html' title='WRITELOG waits'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-4894878007527874610</id><published>2007-05-08T07:54:00.000-07:00</published><updated>2007-05-08T08:00:31.817-07:00</updated><title type='text'>Cool new clustering stuff</title><content type='html'>That I just learned while perusing some Longhorn clustering docs.&lt;br /&gt;&lt;br /&gt;1) GPT cluster disks are now supported.  This should mean no more 2TB limit.&lt;br /&gt;2) The Supported Hardware list is gone - now anything that validates is officially supported.&lt;br /&gt;3) Clustering of virtual servers is now officially supported, so no more hacking virtual disks to get them to show up in multiple virtual instances.  Caveat: The Parallel-SCSI model is deprecated, so it looks like virtual iSCSI is the way to get this to work.&lt;br /&gt;&lt;br /&gt;and my personal favorite, quoted straight from the &lt;a href="http://msmvps.com/blogs/clustering/archive/2007/05/07/cluster-validation-in-windows-server-quot-longhorn-quot-by-jim-teague.aspx"&gt;Q&amp;A session&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;4) "In Windows Server 2003 the way disks were identified was by the Disk Signature. In Longhorn clustered disks are identified by multiple attributes, including the Disk Signature and the SCSI Inquiry data. If a disk can't be found by one attribute, it will attempted to be found in another way. If found the service will self heal and update it's records of the disk. So in Longhorn disks will self heal and should elimate support issues of disk signatures changing and disks not coming online."&lt;br /&gt;&lt;br /&gt;Finally!  No more deleting and re-adding cluster disks when cluster services loses them!&lt;br /&gt;&lt;br /&gt;Longhorn clustering should be cool.  Now I just have to find another cluster to manage.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-4894878007527874610?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/4894878007527874610/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=4894878007527874610' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4894878007527874610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4894878007527874610'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/05/cool-new-clustering-stuff.html' title='Cool new clustering stuff'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2528967211303074854</id><published>2007-04-27T13:30:00.000-07:00</published><updated>2007-04-30T16:15:33.022-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Kerberos'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='IIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Microstrategy'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTP 400'/><title type='text'>Mysterious HTTP 400 errors caused by large Kerberos tickets</title><content type='html'>First off, I know there's been a lack of DBA material lately.  This is because I'm not doing anything interesting, database-wise.  I can tell you all about the woes of interfacing SQL Server with an Oracle system to which I have minimal access and no table schema, but that's pretty boring.&lt;br /&gt;&lt;br /&gt;The most interesting problem I've fixed lately was the mysterious HTTP 400 errors plaguing one of the users of our system.  Briefly, the application consists of a .NET web app that performs business-specific functions and then runs Microstrategy 8.0.1 in an iFrame to run OLAP-style reports.  One of the users of the app was regularly experiencing HTTP 400 errors while using the app, and several others were experiencing these errors intermittently.&lt;br /&gt; &lt;br /&gt;After reading the links below (and a bunch of others), I checked the HTTP error logs at C:\WINNT\system32\LogFiles\HTTPERR and found that the HTTP 400 errors were associated with a RequestLength error type.  According to Microsoft, the default maximum request size is 16384.  I installed Ethereal packet capture software on the QA web server and captured packets while the user attempted to run reports.  A check of the request packets showed that GET requests for certain pages exceeded 16384 bytes immediately before HTTP 400 errors (see image).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_8yUEHkyTv1w/RjZ3DUHlPDI/AAAAAAAAABY/gcBbEGggEhE/s1600-h/large+TCP+request+edited.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_8yUEHkyTv1w/RjZ3DUHlPDI/AAAAAAAAABY/gcBbEGggEhE/s400/large+TCP+request+edited.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5059362130221153330" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I verified this by capturing packets while I ran reports, and my requests were in the 2000-3000 byte range (see image). &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_8yUEHkyTv1w/RjZ3JkHlPEI/AAAAAAAAABg/7Z1HZlulAj4/s1600-h/normal+TCP+request+edited.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_8yUEHkyTv1w/RjZ3JkHlPEI/AAAAAAAAABg/7Z1HZlulAj4/s400/normal+TCP+request+edited.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5059362237595335746" /&gt;&lt;/a&gt;&lt;br /&gt; &lt;br /&gt;Apparently the larger size of his packets could be caused by an excessively large Kerberos authentication ticket combined with cookies and a long request string.  The Kerberos ticket can be larger because of membership in many groups – the user is a member of at least 19 that I can see in Active Directory.  This could be temporarily cleared up in some cases by deleting cookies to reduce request size, which is why I believe that other users who have had this problem have had temporary success at clearing it up by deleting their cookies.  &lt;br /&gt; &lt;br /&gt;According to posts I read on this topic (see the top link for the most useful exchange), using the IP address instead of the hostname will avoid Kerberos ticketing and therefore not cause the problem.  This was the case in our situation – when using the IP address of the QA server, the user had no problems running reports.  He also had no problems after I added the two registry settings above and cycled the required services.  The only alternative I could see was to ask the user to use the IP address of the server instead of the DNS name, but this may be against company policy and would reduce flexibility if we need to change the DNS entry in the future.&lt;br /&gt; &lt;br /&gt;Registry keys added under HKLM\System\CurrentControlSet\Services\HTTP\Parameters&lt;br /&gt; &lt;br /&gt;MaxFieldLength    32768&lt;br /&gt;MaxRequestBytes   32768&lt;br /&gt;&lt;br /&gt;After adding these keys, all users stopped experiencing HTTP 400 errors.&lt;br /&gt; &lt;br /&gt;Main links used for reference:&lt;br /&gt; &lt;br /&gt;&lt;a href="http://www.issociate.de/board/post/314237/HTTP_400_Bad_Request.html"&gt;http://www.issociate.de/board/post/314237/HTTP_400_Bad_Request.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://support.microsoft.com/kb/820129"&gt;http://support.microsoft.com/kb/820129&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/c7d368f0-f175-4d58-b7a8-977e1d67bd07.mspx?mfr=true"&gt;http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/c7d368f0-f175-4d58-b7a8-977e1d67bd07.mspx?mfr=true&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2528967211303074854?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2528967211303074854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2528967211303074854' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2528967211303074854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2528967211303074854'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/04/mysterious-http-400-errors-caused-by.html' title='Mysterious HTTP 400 errors caused by large Kerberos tickets'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_8yUEHkyTv1w/RjZ3DUHlPDI/AAAAAAAAABY/gcBbEGggEhE/s72-c/large+TCP+request+edited.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8683448046820888548</id><published>2007-04-12T15:18:00.000-07:00</published><updated>2007-04-17T06:16:01.104-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hiring'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>Overspecialization</title><content type='html'>My new pet peeve is overspecialization.  &lt;br /&gt;&lt;br /&gt;My esteemed employer emphasizes (at an institutional level) hiring top talent for very specific positions.  I, for example, was hired as a SQL Server 2000 Developer.  I took an extensive test that asked all kinds of very specific SQL Server 2000 questions.  Fine, I know SQL Server, no problem.  &lt;br /&gt;&lt;br /&gt;Then I start work and find out that we're not supposed to touch any low-level SQL stuff because we have a DBA Team for that.  Oookay, I'd rather do these things myself rather than break my train of thought to email somebody, and then wait for them to do something, but I'll give it a shot.&lt;br /&gt;&lt;br /&gt;The first time I had to interact with the DBA team was over an issue with our backups.  They weren't working.  The DBAs have this dramatically complicated procedure that they install on every SQL Server that goes back and retrieves server metadata from a central DB and then dynamically creates a command to back up your databases.  Great, except that it's not flexible enough to keep 3 days worth of backups, which is what we wanted.  So they had a DBA Team member write a customized version of their stored proc that would add a timestamp to the files and then delete the old ones after 3 days.&lt;br /&gt;&lt;br /&gt;Except it didn't work.  I won't go into exactly why, but there were &lt;span style="font-style:italic;"&gt;3 different bugs&lt;/span&gt; within a relatively short stored proc.  So I took it over, re-wrote it from scratch, and now it works fine, completely independent of the metadata repository which wasn't gaining us anything anyway.&lt;br /&gt;&lt;br /&gt;Why did this happen?  Because the guy spends all day every day installing SQL on new servers, installing SPs on old ones, setting up replication, and troubleshooting deadlocks.  And he's probably been doing this for years.  Even if he once was a great developer, skills (like brains) atrophy if unused.  Which is not even his fault, because his job is designed to make him really good at the few things he does and not let him do anything else.&lt;br /&gt;&lt;br /&gt;This causes problems not only for the individual, but for every team.  I'm of the opinion that each team should be capable of functioning as an autonomous unit.  If you need an outside expert occasionally for some piece of knowledge completely outside of your usual purview, fine.  But a team with the skills to accomplish most dev tasks on its own can stay in high gear during development, instead of moving in fits and starts every time it has to beg somebody else to do something.&lt;br /&gt;&lt;br /&gt;Getting back to the individual: of course a broad range of skills is a good thing!  For me, learning new skills is one of the main things that keeps me interested in a job.  Also, every time I interview somebody who has done one thing for his whole career, I have misgivings about hiring him, because &lt;br /&gt;&lt;br /&gt;a) who knows if he can do anything else?&lt;br /&gt;b) he has nothing extra to contribute to the team&lt;br /&gt;c) having only specialized knowledge reduces your creativity when it comes to sticky problems&lt;br /&gt;&lt;br /&gt;My favorite part about CapIQ was getting to work on everything, and in fact one of the reasons that I left was that I felt I was getting pigeon-holed into being just the DB hardware guy.  Little did I know that other offices could be much more restrictive...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8683448046820888548?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8683448046820888548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8683448046820888548' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8683448046820888548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8683448046820888548'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/04/overspecialization.html' title='Overspecialization'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-686448218171598320</id><published>2007-04-11T08:28:00.000-07:00</published><updated>2007-04-11T08:55:39.215-07:00</updated><title type='text'>Infrastructure</title><content type='html'>I was going to post a comment on Allan Leinwand's post titled &lt;a href="http://gigaom.com/2007/04/10/web-20-death-of-the-network-engineer/"&gt;Web 2.0 &amp; Death of the Network Engineer&lt;/a&gt; on &lt;a href="http://www.gigaom.com"&gt;GigaOM&lt;/a&gt;, but there were too many already and I didn't feel like reading them all.  So I'm writing a quick response over here instead.&lt;br /&gt;&lt;br /&gt;The CTO cited in the article knew nothing about the infrastructure details supporting his Web 2.0 venture.  I wish him luck, but I think he's on the path to trouble.  &lt;br /&gt;&lt;br /&gt;The difference between good and great software engineers (or any professional, really) is knowledge of and attention to details.  Anyone can write a stored procedure or a C# app, but a great developer's version will be 10% faster and more stable.  Over time this can translate into huge savings, especially if that piece of code is run 10,000 times (or in some shops, 10,000 times A DAY).  &lt;br /&gt;&lt;br /&gt;Infrastructure works similarly.  Specified, set up, and maintained properly, a company can squeeze maximum performance and capacity out of its infrastructure.  This may not mean much when talking about one $10,000 web server here or there, but let's look at another piece of infrastructure that can make a much bigger difference: database hardware.&lt;br /&gt;&lt;br /&gt;Database servers and disks have been by far the most expensive pieces of hardware owned by each team I've worked on, and the most susceptible to underutilization.  For example, you can buy a 4-socket quad-core Clovertown server with cycles out the wazoo for under $30k, but if you only put $10k into the disks for it, it's not going to do much.  And even if you do put more money into it, you need to know where it's going - will you go with fast, cheap, inflexible SAS storage, a soon-outgrown entry-level SAN like a CX3-10, or a monster DMX3000 but with no budget left over for spindles?  Then when you buy it, who's going to have the knowledge to set it up so that it performs properly?  If you dump all your DBs on one set of disks, you're potentially giving up a lot of performance, which means you'll have to buy more disks constantly as you scale up your user base.  &lt;br /&gt;&lt;br /&gt;A CTO who doesn't know these things is bad enough, but one who doesn't care is potentially leading his company into a financial quagmire.  If you don't know what you're doing, it's easy to spend millions on infrastructure when you could have spent thousands.  And the difference is knowing what you need and knowing how to use it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-686448218171598320?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/686448218171598320/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=686448218171598320' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/686448218171598320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/686448218171598320'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/04/infrastructure.html' title='Infrastructure'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-425207549617030379</id><published>2007-03-29T11:15:00.000-07:00</published><updated>2007-03-29T11:24:02.292-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IBM'/><category scheme='http://www.blogger.com/atom/ns#' term='Thinkpad'/><category scheme='http://www.blogger.com/atom/ns#' term='T20'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows XP'/><title type='text'>Old Thinkpad Nightmares</title><content type='html'>This is barely relevant to anything, I just want to get this information out on the net.  &lt;br /&gt;&lt;br /&gt;If you are having problems installing a fresh copy of Windows XP on an IBM Thinkpad T20 because the windows installer / setup program crashes repeatedly in random places, this is the fix:&lt;br /&gt;&lt;br /&gt;Remove the battery.&lt;br /&gt;&lt;br /&gt;I don't know why it works, but I'm guessing something to do with either power management drivers or CPU speed-stepping.  I spent probably 6 hours thrashing on this stupid thing before locating an obscure post on an MIT newsgroup.  Hopefully this blog will be slightly easier to find if anyone else is ever doing this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-425207549617030379?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/425207549617030379/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=425207549617030379' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/425207549617030379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/425207549617030379'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/03/old-thinkpad-nightmares.html' title='Old Thinkpad Nightmares'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2542182737887237695</id><published>2007-03-15T08:58:00.000-07:00</published><updated>2007-03-15T09:31:04.600-07:00</updated><title type='text'>Too Much Information</title><content type='html'>I've noticed lately that my &lt;a href="http://www.google.com/reader"&gt;Google Reader&lt;/a&gt; inbox is more full than ever.  It's not because of all the new feeds I'm adding - I've actually unsubscribed from a number of them.  I don't have stats to back this up, but I believe it's because overall post volume on many blogs and news sites is increasing.  &lt;br /&gt;&lt;br /&gt;Fine.  I like to stay informed, who doesn't?&lt;br /&gt;&lt;br /&gt;Except that a lot of these posts are just for the sake of posting.  When I read about disaster preparedness on &lt;a href="http://www.seekingalpha.com"&gt;Seeking Alpha&lt;/a&gt; and entertainment news (read: gossip) on &lt;a href="http://www.theregister.co.uk"&gt;The Register&lt;/a&gt;, something is wrong.  &lt;br /&gt;&lt;br /&gt;My friend Kevin Ho hates mainstream media.  I disagree with him on most of his reasons, but he always points out that when the average person reads a newspaper article, he accepts that the facts and general position presented therein are accurate.  Until he reads an article about a topic that he knows something about, and then he says, "What are these idiots talking about? They're missing the point entirely!" &lt;br /&gt;&lt;br /&gt;Which is one of the reasons why I love blogs - it allows an expert in a certain subject to post about topics in an area in which he/she has extensive knowledge.  And then I can aggregate the topics I care about in my RSS reader.  No more amateurs writing about topics in which they have little background or understanding.&lt;br /&gt;&lt;br /&gt;Unfortunately, many of these sites seem to be getting a big head about their traffic numbers and have started to assume that their readers live on their sites and go nowhere else, or else are attempting to squeeze more pageviews to generate those all-important ad dollars.  At least, those are the possible rationales I've come up with for their explosions in posting, especially about topics outside their areas of expertise.  Posts which are at best misguided, and at worst spam.&lt;br /&gt;&lt;br /&gt;Even posts within a site's usual topical areas can be annoying if they're frivolous.  For example, tech news outlets &lt;a href="http://www.theregister.co.uk"&gt;The Register&lt;/a&gt; and &lt;a href="http://www.theinquirer.co.uk"&gt;The Inquirer&lt;/a&gt; both post about 30-40 articles per day.  Occasionally I'll click through to one with an interesting title, only to find that it's one paragraph long and contains no real information.  Leave it out!&lt;br /&gt;&lt;br /&gt;Mind you, I'm okay with a breadth of posts on personal blogs - the volume is low enough that ignoring the chaff doesn't take long, and some of it may even be interesting.  And not all big sites are guilty of this posting diarrhea - &lt;a href="http://www.pitchforkmedia.com"&gt;Pitchfork&lt;/a&gt; only posts about music, &lt;a href="http://www.tomshardware.com"&gt;Tom's Hardware&lt;/a&gt; about computer hardware, &lt;a href="http://www.therealdeal.net"&gt;The Real Deal&lt;/a&gt; about real estate.  But sites like &lt;a href="http://www.jalopnik.com"&gt;Jalopnik&lt;/a&gt; and &lt;a href="http://www.gigaom"&gt;GigaOM&lt;/a&gt;, you're on notice.  Keep up the crappy posts, and I'm dropping your feed.  &lt;br /&gt;&lt;br /&gt;(Yes, I realize that by posting this I'm guilty of the offense about which I'm complaining. I'm okay with the hypocrisy.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2542182737887237695?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2542182737887237695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2542182737887237695'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/03/too-much-information.html' title='Too Much Information'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-7086151862446810585</id><published>2007-02-14T08:26:00.000-08:00</published><updated>2007-02-20T12:27:19.008-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>"Unable to perform a SETUSER to the requested username" error</title><content type='html'>This was a new one on me:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_8yUEHkyTv1w/RdM5lbGzO2I/AAAAAAAAAAw/MkuGCGj-Ca0/s1600-h/SETUSER+error+msg.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_8yUEHkyTv1w/RdM5lbGzO2I/AAAAAAAAAAw/MkuGCGj-Ca0/s320/SETUSER+error+msg.png" alt="" id="BLOGGER_PHOTO_ID_5031428523797199714" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Backstory: We have an application that runs a SQL job every time a set of data is checked out.  (I didn't design it.)  Our development server was recently demolished by the SAN team while they were trying to add a new HBA, so it had to be rebuilt from scratch.  After the rebuild, SQL was at version 8.0.2039 (SP4 w/ no hotfixes) and the job wouldn't run.  It would spit out the above error each time, which was breaking the app.&lt;br /&gt;&lt;br /&gt;This error looked like a permissions issue to me, so I started out by checking the user mapping.  We'll call the login that runs the application "CORP\AppUser."  This user was a member of dbowner in the database in the job step, so that wasn't the problem.  Tried sp_start_job from Query Analyzer using those credentials, which worked, but still produced the error.  Tried starting the job using my credentials instead, which produced the same error.  &lt;br /&gt;&lt;br /&gt;Then I changed the job owner to the same account that SQLAgent runs under, and the job worked.  So it was definitely a permissions issue.  I decided to check out the specific sequence of events underneath firing off a job, so I ran a Profiler trace and found this...&lt;br /&gt;&lt;br /&gt;exec sp_setuserbylogin N'CORP\AppUser', 1&lt;br /&gt;&lt;br /&gt;Hmm, what's that?  It's not in BOL, and I couldn't find it in the master DB.  But clearly SQL is trying to execute it, which might explain why the error it's returning is looking for user ''.  I dug around a bit more and found some code to add it back into master.&lt;br /&gt;&lt;br /&gt;exec sp_addextendedproc N'sp_setuserbylogin', N'(server internal)'&lt;br /&gt;&lt;br /&gt;Voila!  As soon as I ran this code, the job worked like a charm.  Apparently a botched SP3 or 4 install can miss this proc, which is what probably happened here.  So if you come across this error, make sure you've got sp_setuserbylogin properly installed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-7086151862446810585?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/7086151862446810585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=7086151862446810585' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7086151862446810585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/7086151862446810585'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/02/setuser-error.html' title='&quot;Unable to perform a SETUSER to the requested username&quot; error'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_8yUEHkyTv1w/RdM5lbGzO2I/AAAAAAAAAAw/MkuGCGj-Ca0/s72-c/SETUSER+error+msg.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8439433009895202005</id><published>2007-01-31T15:16:00.000-08:00</published><updated>2007-02-20T12:26:35.208-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='vbscript'/><category scheme='http://www.blogger.com/atom/ns#' term='dts'/><title type='text'>Stupid general-purpose connection errors</title><content type='html'>Had to debug a stupid error today being thrown by the VBscript we use to deploy DTS packages.  Here's the text of the error:&lt;br /&gt;&lt;br /&gt;[DBNETLIB][ConnectionRead (WrapperRead()).]&lt;br /&gt;&lt;br /&gt;Pretty helpful, huh? &lt;br /&gt;&lt;br /&gt;Although it wasn't difficult to debug after I got access to the script source.  Here's the line that was producing the error:&lt;br /&gt;&lt;br /&gt;Set oPackageSQLServer = oApplication.GetPackageSQLServer(sDestServer, sUser , sPwd , 0)&lt;br /&gt;&lt;br /&gt;I tried connecting to the server using the same credentials, which broke with another unhelpful error.  Then I logged into the server directly and tried logging in there, where it informed me that the default database for that user was unavailable.  Aha!  That DB was in the middle of a restore.  So I changed the default database and was able to transfer packages. &lt;br /&gt;&lt;br /&gt;I'm posting this so that somebody trying to track down this error with the PackageSQLServer object might land here and see this message:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Check your login credentials!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8439433009895202005?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8439433009895202005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8439433009895202005' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8439433009895202005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8439433009895202005'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/01/stupid-general-purpose-connection.html' title='Stupid general-purpose connection errors'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-8162319558466955572</id><published>2007-01-30T08:09:00.000-08:00</published><updated>2007-02-20T11:36:56.733-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DBA tools'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>Blocking Chain script</title><content type='html'>I had a need to follow some quickly changing blocking chains today, and couldn't find any simple blocking chain scripts that I liked, so I wrote one.  It's not the prettiest method, but it's simple, easy to modify, and doesn't rely on lots of hard-to-debug dynamic SQL.&lt;br /&gt;&lt;br /&gt;The next updates I'll probably make will be to display only the top-level blockers rather than all blocking chains, and to get rid of the 0s at the end of each blocking chain line.&lt;br /&gt;&lt;br /&gt;Here's the SQL:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;if object_id('tempdb..#blockers0') is not null&lt;br /&gt;drop table #blockingchain&lt;br /&gt;&lt;br /&gt;create table #blockingchain&lt;br /&gt;(&lt;br /&gt;blockingchain varchar(255)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;insert into #blockingchain&lt;br /&gt;select cast(spid as varchar(5)) + ' -&gt; ' + cast(blocked as varchar(5))&lt;br /&gt;from master..sysprocesses&lt;br /&gt;where blocked &lt;&gt; 0&lt;br /&gt;&lt;br /&gt;while exists (select 1 from #blockingchain where cast((substring(right(blockingchain, 5), 1 + charindex('&gt;', right(blockingchain, 5)), 5)) as smallint) &lt;&gt; 0)&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;update bc set blockingchain = blockingchain + ' -&gt; ' + cast(sp.blocked as varchar(5))&lt;br /&gt;  from #blockingchain bc&lt;br /&gt;  inner join master..sysprocesses sp&lt;br /&gt;          on cast((substring(right(bc.blockingchain, 5), 1 + charindex('&gt;', right(bc.blockingchain, 5)), 5)) as smallint) = sp.spid&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;select * from #blockingchain&lt;br /&gt;order by len(blockingchain) asc,&lt;br /&gt;substring(blockingchain, 1, charindex('-', blockingchain)) asc&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Sample output:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_8yUEHkyTv1w/Rb9v1bZcYjI/AAAAAAAAAAk/MZYdKSnn-Zc/s1600-h/blockingchain.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_8yUEHkyTv1w/Rb9v1bZcYjI/AAAAAAAAAAk/MZYdKSnn-Zc/s320/blockingchain.png" alt="" id="BLOGGER_PHOTO_ID_5025858672846987826" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-8162319558466955572?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/8162319558466955572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=8162319558466955572' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8162319558466955572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/8162319558466955572'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/01/blocking-chain-script.html' title='Blocking Chain script'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_8yUEHkyTv1w/Rb9v1bZcYjI/AAAAAAAAAAk/MZYdKSnn-Zc/s72-c/blockingchain.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-4792602064915976832</id><published>2007-01-17T08:31:00.000-08:00</published><updated>2007-02-20T11:36:03.740-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='clusters'/><category scheme='http://www.blogger.com/atom/ns#' term='Active Directory'/><title type='text'>Changing the Domain for a SQL 2005 Cluster</title><content type='html'>&lt;span style="font-weight: bold;font-size:78%;" &gt;NOTE: It looks like my old DBAIQ blog may be down for the count due to Blogger issues, and I didn't want to lose my post on changing the domain for a SQL 2005 cluster, so I retrieved it from Google's search cache, and am reprinting it here.  Ironic that Google was both the cause of its destruction (taking over Blogger and breaking our team blog) and its recovery (search cache).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We're moving our Dev environment to a new domain for some unfathomable corporate reason, and it's going to be a major headache.  Among our 20+ SQL Servers in the environment, we've got a few SQL 2005 clusters.  According to Microsoft, we can't move them without uninstalling SQL.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.microsoft.com/kb/915846/en-us"&gt;http://support.microsoft.com/kb/915846/en-us&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Needless to say, this would add more pain to the migration process. It wouldn't be the end of the world, but this is weekend work, and uninstalling and re-installing a couple active/active SQL clusters is just the thing to turn 1 day of work into 2+.&lt;br /&gt;&lt;br /&gt;However, I think they're wrong.&lt;br /&gt;&lt;br /&gt;I built two virtual machines on VMWare Server, added them to a cluster (see &lt;a href="http://sqladvice.com/blogs/repeatableread/archive/2005/08/01/4273.aspx"&gt;Repeatable Read&lt;/a&gt; for instructions on creating shared disks in VMWare) on our current domain, and created some databases.  Verified failover capability and connectivity.&lt;br /&gt;&lt;br /&gt;Then I moved both nodes to the new domain using the following steps:&lt;br /&gt;&lt;br /&gt;1) Take all cluster resources offline (except the quorum, which cannot be taken offline)&lt;br /&gt;2) Stop the cluster service on both nodes&lt;br /&gt;3) Change the cluster service startup type to Manual&lt;br /&gt;4) Change the domain of each machine to the new domain and reboot&lt;br /&gt;5) After reboot, on each machine, change the cluster and SQL service accounts to accounts in the new domain&lt;br /&gt;6) Run gpedit.msc or otherwise access Local Security Policy Settings (see below), and grant the following rights:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Cluster Service Account&lt;/strong&gt;&lt;br /&gt;Act as part of the operating system&lt;br /&gt;Adjust memory quotas for a process&lt;br /&gt;Debug programs&lt;br /&gt;Increase scheduling priority&lt;br /&gt;Manage auditing and security log&lt;br /&gt;Restore files and directories&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;SQL Service Account&lt;/strong&gt;&lt;br /&gt;Adjust memory quotas for a process&lt;br /&gt;Lock pages in memory&lt;br /&gt;Log on as a batch job&lt;br /&gt;Log on as a service&lt;br /&gt;Replace a process level token&lt;br /&gt;&lt;br /&gt;&lt;div align="center"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/7034/1592/1600/gpedit.jpg" alt="" border="0" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;7) Add the cluster and SQL service accounts to the local Adminstrators group.  NOTE: This should not be necessary for SQL, and I will update this with the minimum required permissions as soon as I sort them out. It is necessary for the cluster account, however.&lt;br /&gt;8) Start the cluster service on both machines&lt;br /&gt;9) Bring cluster resources online&lt;br /&gt;10) Go enjoy the rest of your weekend&lt;br /&gt;&lt;br /&gt;If you missed some permissions, the cluster service will likely fail to start with an error 7023 or 1321, and will helpfully output an error in the system log with eventId 1234 that contains a list of the necessary user rights that still need to be assigned. Now that's error reporting!&lt;br /&gt;&lt;br /&gt;Comprehensive testing is still pending, but the preliminary results look good.  After this process, SQL Server comes online on my test cluster, as do SQL Agent and Fulltext.  I don't have any machines on the new domain with SQL Management Studio installed, but I could connect to SQL using osql directly on one of the cluster nodes. If anyone out there has any different experiences or comments, I'd love to hear them.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt;&lt;br /&gt;My previous post left out one small but significant detail: the domain groups under which the SQL Server service accounts run.  When one installs SQL 2005 on a cluster, the setup program requires domain groups to be entered for each service account.  So for example:&lt;br /&gt;&lt;br /&gt;SQL Server service account: OLDDOMAIN\SQLService&lt;br /&gt;SQL Agent service account: OLDDOMAIN\SQLAgentService&lt;br /&gt;SQL Browser service account: OLDDOMAIN\SQLBrowserService&lt;br /&gt;&lt;br /&gt;Domain groups:&lt;br /&gt;&lt;br /&gt;OLDDOMAIN\SQLServiceGroup&lt;br /&gt;OLDDOMAIN\SQLAgentServiceGroup&lt;br /&gt;OLDDOMAIN\FullTextGroup&lt;br /&gt;&lt;br /&gt;Then it comes time to move your cluster, and you've followed my steps above or done your own hacking, and you've changed the service accounts to NEWDOMAIN\SQLService and so on. But the domain groups remain the same.  Your cluster will come online and fail over and operate fine, but you won't be able to change it.&lt;br /&gt;&lt;br /&gt;This was made evident when I tried to add a node to an existing cluster after moving it to a new domain. It gave me a message like "Cannot add NEWDOMAIN\SQLService to OLDDOMAIN\SQLServiceGroup." Arrgh. Microsoft had already claimed that this was not supported, so I suppose I shouldn't have been surprised.&lt;br /&gt;&lt;br /&gt;So I started searching for the reference to OLDDOMAIN\SQLServiceGroup. And couldn't find it. Not in a config file, or a system table (I know, that was dumb, but I was desperate), or the registry, where I expected to find it. Eventually, I started combing the registry key by key within the SQL hives and came across this in HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\Setup...&lt;br /&gt;&lt;br /&gt;(okay, I tried to upload another image here to illustrate, but Blogger hates me, so screw it.)&lt;br /&gt;&lt;br /&gt;The keys AGTGroup, FTSGroup, and SQLGroup contain the SIDs for whatever OLDDOMAIN groups you set up when installing SQL. Find the SIDs for your new domain groups (the VBScript below is how I did it), enter those in place of the old ones, restart SQL, and your cluster is moved. You should now be able to add or remove nodes, install hotfixes, etc. You'll need to update the SIDs for each SQL installation (MSSQL.2, MSSQL.3, etc.)&lt;br /&gt;&lt;br /&gt;As with any unsupported operation, your mileage may vary, but let me know if you have a different experience with this or you run into additional problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-4792602064915976832?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/4792602064915976832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=4792602064915976832' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4792602064915976832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4792602064915976832'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/01/changing-domain-for-sql-2005-cluster.html' title='Changing the Domain for a SQL 2005 Cluster'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2388985125397844897</id><published>2007-01-17T07:56:00.000-08:00</published><updated>2007-02-20T11:35:09.951-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='litespeed'/><category scheme='http://www.blogger.com/atom/ns#' term='backups'/><title type='text'>SQL Litespeed works better when unregistered</title><content type='html'>I recently set up a new DR server that had recently been built from scratch, and the DBAs who set it up didn't have a product key for SQL Litespeed, which we use to backup all of our databases.  If you don't know about &lt;a href="http://www.quest.com/litespeed_for_sql_server/"&gt;Litespeed&lt;/a&gt;, go check it out, it's handy.  So the DBAs set it up using a trial version of the software.&lt;br /&gt;&lt;br /&gt;After that, I set up an automatic restore process on the DR servers, but it was taking forever.  A backup that would restore in 4-5 hours on the hardware-inferior DR QA server would take 18-20 hours on the Production DR server.  This gave us a potentially long recovery time and precluded using the DR machine for reporting or other tasks.  I ran a series of diagnostics against the server, and eventually even involved the SAN team, but everything looked fine - disk queues and CPU usage were low, the drives were clearly capable of much higher IOs, etc.&lt;br /&gt;&lt;br /&gt;Then one day, the restores sped up.  Not by a little bit, but by 10x - from 18 hours to 85-90 minutes.  Hey, cool.  Except I didn't know what had happened.  But it was working and I had other stuff to do, so I left it alone.&lt;br /&gt;&lt;br /&gt;A week later, I attempted to take a backup of a DB on that server and got an error message informing me that SQL Litespeed's trial period had expired.  I checked that the backups were still restoring, which they were, and sent another request for a Litespeed license.&lt;br /&gt;&lt;br /&gt;The request came through a few weeks later, and on the day that Litespeed was officially registered, the backups started taking 18 hours again.  Bizarre?  Yeah.  I'm tempted to uninstall the licensed version and run it in trial mode again unless Quest can give me a good explanation as to why this is happening and how to fix it.&lt;br /&gt;&lt;br /&gt;Here's some sample output from Litespeed on our server, with sensitive data redacted.  Emphasis is mine.&lt;br /&gt;&lt;br /&gt;Executed as user: [user]. Warning: Null value is eliminated by an aggregate or other SET operation. [SQLSTATE 01003] (Message 8153)  Processed 29616984 pages for database '[dbname]', file '[dbname]_Data' on file 1. Processed 26037664 pages for database '[dbname]', file '[dbname]_Data2' on file 1. Processed 23631992 pages for database '[dbname]', file '[dbname]_Data3' on file 1. Processed 16 pages for database '[dbname]', file '[dbname]_Log' on file 1. RESTORE DATABASE successfully processed 79286656 pages in &lt;span style="font-weight: bold;"&gt;5051.204&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;seconds&lt;/span&gt; (&lt;span style="font-weight: bold;"&gt;128.586 MB/sec&lt;/span&gt;).  CPU Seconds: 8190.55 Environment: Intel(R) Xeon(TM) MP CPU 3.00GHz CPUs: 8 logical, 8 cores, 8 physical packages. [SQLSTATE 01000] (Message 1).  The step succeeded.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Executed as user: [user]. Warning: Null value is eliminated by an aggregate or other SET operation. [SQLSTATE 01003] (Message 8153)  Processed 29616984 pages for database '[dbname]', file '[dbname]_Data' on file 1. Processed 26037664 pages for database '[dbname]', file '[dbname]_Data2' on file 1. Processed 23631992 pages for database '[dbname]', file '[dbname]_Data3' on file 1. Processed 16 pages for database '[dbname]', file '[dbname]_Log' on file 1. RESTORE DATABASE successfully processed 79286656 pages in &lt;span style="font-weight: bold;"&gt;69992.264 seconds&lt;/span&gt; (&lt;span style="font-weight: bold;"&gt;9.279 MB/sec&lt;/span&gt;).  CPU Seconds: 7422.05 Environment: Intel(R) Xeon(TM) MP CPU 3.00GHz CPUs: 8 logical, 8 cores, 8 physical packages. [SQLSTATE 01000] (Message 1).  The step succeeded.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2388985125397844897?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2388985125397844897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2388985125397844897' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2388985125397844897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2388985125397844897'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2007/01/sql-litespeed-works-better-when.html' title='SQL Litespeed works better when unregistered'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-1463129258425196673</id><published>2006-12-18T10:30:00.000-08:00</published><updated>2008-03-12T07:57:46.278-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='audio'/><category scheme='http://www.blogger.com/atom/ns#' term='home theater'/><title type='text'>Work in Progress: Ira's Home Theater</title><content type='html'>As  it says in my profile, I'm an audiophile and an equipment junkie, so I had to post(/brag) about my home theater system.  It's not the most expensive setup around, but it sounds pretty damn good for anything from Autechre to zydeco, and The Matrix shakes the floor.&lt;br /&gt;&lt;br /&gt;Speakers&lt;br /&gt;2x &lt;a href="http://www.jblpro.com/pages/recording/lsr32.htm"&gt;JBL LSR32s&lt;/a&gt;&lt;br /&gt;2x Bose 301 (my roommate's old speakers, being used as surrounds)&lt;br /&gt;1x B&amp;W CC6 center channel&lt;br /&gt;1x &lt;a href="http://www.aguilaramp.com/products_cabinets_gs212.htm"&gt;Aguilar GS212&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Amps&lt;br /&gt;&lt;del&gt;1x TEAC POS receiver&lt;/del&gt;&lt;br /&gt;1x Harman Kardon AVR 330&lt;br /&gt;1x &lt;a href="http://www.crownaudio.com/amp_htm/k.htm"&gt;Crown K1&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://www.swrsound.com/products/search.php?partno=4400500000"&gt;SWR 750x&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Power&lt;br /&gt;1x &lt;a href="http://www.monstercable.com/productdisplay.asp?pin=3259"&gt;Monster Power HTS 3600&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Interconnects&lt;br /&gt;Tara Labs Prism Omni speaker cables, Canare L-2T2S interconnects, Vampire, Homegrown, and Canare connectors, all hand-terminated with Cardas or Kester solder&lt;br /&gt;&lt;br /&gt;Display&lt;br /&gt;&lt;del&gt;1x &lt;a href="http://www.westinghousedigital.com/details.aspx?itemnum=26"&gt;Westinghouse LVM37-w1&lt;/a&gt;&lt;/del&gt;&lt;br /&gt;1x &lt;a href="http://www.samsung.com/us/consumer/detail/detail.do?group=televisions&amp;type=televisions&amp;subtype=lcdtv&amp;model_cd=LNT5265FX/XAA"&gt;Samsung LN-T5265F&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Sources&lt;br /&gt;1x &lt;a href="http://www.xbox.com/xbox360"&gt;XBox 360&lt;/a&gt;&lt;br /&gt;1x HTPC running &lt;del&gt;Windows XP&lt;/del&gt; Windows Vista Ultimate&lt;br /&gt;1x Scientific Atlanta 8300 HDC&lt;br /&gt;&lt;br /&gt;Miscellaneous&lt;br /&gt;1x Logitech Harmony 890 universal remote&lt;br /&gt;&lt;del&gt;2x nameless black wood speaker stands&lt;/del&gt;&lt;br /&gt;2x American Recording Technologies studio monitor stands&lt;br /&gt;&lt;br /&gt;UPDATE (1/15/07):&lt;br /&gt;Picked up a Harman Kardon AVR 330.  The 645 was overkill for what I wanted, since I don't use HDMI at this point, and the 330 was a steal.  I also got a pair of JBL E30s with it, which I'll either use as surrounds or give to my parents.&lt;br /&gt;&lt;br /&gt;UPDATE 2 (2/13/07):&lt;br /&gt;Found a mint B&amp;amp;W CC6 center channel.  It's not quite as high-end as I was planning to go, but there's not enough space for a big center speaker, so this one will do nicely until I buy a warehouse.  And then I'll just outfit the whole place with Turbosound.&lt;br /&gt;&lt;br /&gt;UPDATE 3 (3/12/08):&lt;br /&gt;Well, the Westinghouse TV blew up, but my roommate got his bonus and replaced it with a 52" Samsung that looks quite good on the wall of our new place.  I picked up an SWR 750x and an Aguilar GS212 to play my bass through, and that stack is pulling double-duty as a massively overpowered subwoofer.  Also got a Monster HTS 3600, mainly so that I could switch off the Crown using a remote.  And finally, we got a new couch that sits in the way of the audio rack, so I just HAD to get a Logitech Harmony 890 to control the whole system via RF (and the one-button system configuration is nice, too). Converted all the display cables, too - the 360 now displays via VGA, the Scientific Atlanta PVR via HDMI, and the HTPC via DVI-&gt;HDMI.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-1463129258425196673?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/1463129258425196673/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=1463129258425196673' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1463129258425196673'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/1463129258425196673'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2006/12/work-in-progress-iras-home-theater.html' title='Work in Progress: Ira&apos;s Home Theater'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2612017204857002514</id><published>2006-12-18T08:02:00.000-08:00</published><updated>2007-02-20T11:31:47.115-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='tempdb'/><title type='text'>Lists vs. temp tables</title><content type='html'>Dynamic SQL is in heavy use at my new office, and I'm not sure how I feel about a lot of it.  For example, one of my coworkers showed me a neat trick by which one can append to a string with each successive row returned in a select statement, like so:&lt;br /&gt;&lt;br /&gt;select @list = @list + cast(foo as varchar(10)) + ',' from #test2&lt;br /&gt;&lt;br /&gt;But I noticed that this technique was used in many pieces of code in our system, and it bothered me, because I was pretty sure that creating and joining to temp tables would be faster than assembling long strings and then using them with "in" clauses.  I wasn't positive, however, so I assembled this test script:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family:Courier;"&gt;&lt;br /&gt;SET NOCOUNT ON&lt;br /&gt;&lt;br /&gt;if OBJECT_ID('tempdb..#timing') is not null&lt;br /&gt;drop table #timing&lt;br /&gt;&lt;br /&gt;if OBJECT_ID('tempdb..#test1') is not null&lt;br /&gt;drop table #test1&lt;br /&gt;&lt;br /&gt;if OBJECT_ID('tempdb..#test2') is not null&lt;br /&gt;drop table #test2&lt;br /&gt;&lt;br /&gt;declare&lt;br /&gt;@i int&lt;br /&gt;, @items int&lt;br /&gt;&lt;br /&gt;set @items = 1022&lt;br /&gt;&lt;br /&gt;create table #timing&lt;br /&gt;(&lt;br /&gt;testrun varchar(100)&lt;br /&gt;, setupStartTime datetime&lt;br /&gt;, setupEndTime datetime&lt;br /&gt;, setupElapsed as datediff(ms, setupStartTime, setupEndTime)&lt;br /&gt;, queryStartTime datetime&lt;br /&gt;, queryEndTime datetime&lt;br /&gt;, queryElapsed as datediff(ms, queryStartTime, queryEndTime)&lt;br /&gt;, totalElapsed as datediff(ms, setupStartTime, setupEndTime) + datediff(ms, queryStartTime, queryEndTime)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;select&lt;br /&gt;identity(int, 10403, 96) as foo&lt;br /&gt;, cast('some text' as varchar(20)) as bar&lt;br /&gt;into&lt;br /&gt;#test1&lt;br /&gt;&lt;br /&gt;set @i = 0&lt;br /&gt;&lt;br /&gt;while @i &lt; @items begin     insert into #test1 select 'cowabunga'     set @i = @i + 1 end  insert into #timing (testRun, setupStartTime) values ('Temp Table', getDate())  select foo into #test2 from #test1  create clustered index ix on #test2 (foo)  update #timing set setupEndTime = getDate() where testRun = 'Temp Table'  create clustered index ix on #test1 (foo)   insert into #timing (testRun, setupStartTime) values ('List', getDate())  declare @list varchar(7000), @curID int set @list = '('  select @curID = min(foo) from #test2  --while @curID is not null --begin --    select @list = @list + cast(@curId as varchar(10)) + ',' --    select @curId = min(foo) from #test2 where foo &gt; @curID&lt;br /&gt;--end&lt;br /&gt;&lt;br /&gt;select @list = @list + cast(foo as varchar(10)) + ',' from #test2&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;set @list = substring(@list, 0, len(@list) - 1)  + ')'&lt;br /&gt;&lt;br /&gt;declare @sql varchar(8000)&lt;br /&gt;set @sql = 'select * from #test1 where foo in ' + @list&lt;br /&gt;&lt;br /&gt;update #timing&lt;br /&gt;set setupEndTime = getDate()&lt;br /&gt;where testRun = 'List'&lt;br /&gt;&lt;br /&gt;print(@sql)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;update #timing&lt;br /&gt;set queryStartTime = getDate()&lt;br /&gt;where testRun = 'List'&lt;br /&gt;&lt;br /&gt;exec (@sql)&lt;br /&gt;&lt;br /&gt;update #timing&lt;br /&gt;set queryEndTime = getDate()&lt;br /&gt;where testRun = 'List'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;update #timing&lt;br /&gt;set queryStartTime = getDate()&lt;br /&gt;where testRun = 'Temp Table'&lt;br /&gt;&lt;br /&gt;select t1.* from #test1 t1&lt;br /&gt;inner join #test2 t2&lt;br /&gt;on t1.foo = t2.foo&lt;br /&gt;&lt;br /&gt;update #timing&lt;br /&gt;set queryEndTime = getDate()&lt;br /&gt;where testRun = 'Temp Table'&lt;br /&gt;&lt;br /&gt;select * from #timing&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;The results of this test vary somewhat, so it would be best to run the whole thing in a loop to assemble a statistically valid set of data, but the difference between the two methods is so pronounced that the SD doesn't really matter.  Ready for the (approximate) difference?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Temp tables are 3x faster then strings.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's a typical result of this script running on our QA server, an 8-CPU 20-GB box running SQL 2000 build 2171:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_8yUEHkyTv1w/RYbFDQH5ZqI/AAAAAAAAAAU/BGjFpuPij5I/s1600-h/temp+tables+vs+lists+timing.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_8yUEHkyTv1w/RYbFDQH5ZqI/AAAAAAAAAAU/BGjFpuPij5I/s320/temp+tables+vs+lists+timing.png" alt="" id="BLOGGER_PHOTO_ID_5009908295154624162" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Running it repeatedly yielded similar results with some higher outliers, but very few lower ones.  The next problem will be how to propose changing our coding practices and re-writing a lot of stored procs.  Stay tuned for that one, and possibly an entry about my subsequent de-hiring.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2612017204857002514?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2612017204857002514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2612017204857002514' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2612017204857002514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2612017204857002514'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2006/12/lists-vs-temp-tables.html' title='Lists vs. temp tables'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_8yUEHkyTv1w/RYbFDQH5ZqI/AAAAAAAAAAU/BGjFpuPij5I/s72-c/temp+tables+vs+lists+timing.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-5006359748737322343</id><published>2006-12-12T12:16:00.000-08:00</published><updated>2007-02-20T12:26:05.478-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DBA tools'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='replication'/><title type='text'>Shrinking log files of formerly replicated DBs</title><content type='html'>To start, I should note that a) there's probably a better way to do this, and b) I'm sure this is already out on the net somewhere, possibly even on my old blog as a post from Mike Forman.  But this way works, it's fast, and I couldn't Google it when I needed it, so I'm posting it again.&lt;br /&gt;&lt;br /&gt;In our QA Static and Dev environments, we have static copies of a DB that is a replication subscriber in Production.  This DB gets refreshed (restored) from Production every few weeks, or when I break everything and have to restore a fresh copy.  When restored, it still has transactions marked as pending replication in the log, and so the log cannot be shrunk.&lt;br /&gt;&lt;br /&gt;Naturally, we don't have as much space as we'd like in QA and Dev, and since the DB in question is static, it doesn't need the 50 GB transaction log that it has in Production.  So I wanted to shrink the transaction log, but was prevented from doing so by this error:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cannot shrink log file 4 (Test_Log1) because all logical log files are in use.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;So how do you fix this?&lt;br /&gt;&lt;br /&gt;My solution was to fool (read: hack) the system tables to make SQL think this DB was still a replication subscriber, then use sp_repldone to set all the transactions to done.  This short script will do it, although I recommend you BE CAREFUL, because this is the master database you're messing with.&lt;br /&gt;&lt;br /&gt;sp_configure 'allow updates', 1&lt;br /&gt;reconfigure with override&lt;br /&gt;&lt;br /&gt;update master.dbo.sysdatabases set category = 1 --&lt;br /&gt;where dbid = 10 -- replace with appropriate dbid for your DB&lt;br /&gt;&lt;br /&gt;use Test&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;EXEC sp_repldone @xactid = NULL, @xact_segno = NULL, @numtrans = 0, @time = 0, @reset = 1&lt;br /&gt;&lt;br /&gt;update master.dbo.sysdatabases set category = 0&lt;br /&gt;where dbid = 10 -- ditto&lt;br /&gt;&lt;br /&gt;sp_configure 'allow updates', 0&lt;br /&gt;reconfigure with override&lt;br /&gt;&lt;br /&gt;After the sp_repldone, you'll be able to shrink the log file to your heart's content.  There may be another way to do this, such as attaching the DB without its log file, but I'm not sure that works, and besides, I like hacking system tables.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-5006359748737322343?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/5006359748737322343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=5006359748737322343' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5006359748737322343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/5006359748737322343'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2006/12/shrinking-log-files-of-formerly.html' title='Shrinking log files of formerly replicated DBs'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-2926230237386766255</id><published>2006-12-07T06:35:00.000-08:00</published><updated>2007-02-20T11:32:39.178-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Management Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Retrieve queries when SMS crashes</title><content type='html'>I can never remember where the .sql temp files are stored by SQL Management Studio so that I can retrieve queries-in-progress when it crashes.  So I'm blogging this so I can find it later. &lt;br /&gt;&lt;br /&gt;This time, at least, the files were in the following path:&lt;br /&gt;&lt;br /&gt;C:\Documents and Settings\[user name]\My Documents\SQL Server Management Studio\Backup Files\Solution1&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-2926230237386766255?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/2926230237386766255/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=2926230237386766255' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2926230237386766255'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/2926230237386766255'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2006/12/retrieve-queries-when-sms-crashes.html' title='Retrieve queries when SMS crashes'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2021989930591302225.post-4205874397919231627</id><published>2006-12-04T08:27:00.000-08:00</published><updated>2006-12-04T08:40:37.596-08:00</updated><title type='text'>Start me up</title><content type='html'>I'm firing up another DBA blog, one that I'll hopefully be able to hang onto this time.  I used to be the primary (or at least most prolific) contributor to &lt;a href="http://dbaiq.blogspot.com"&gt;DBA IQ&lt;/a&gt;, but I've moved on from that blog for two reasons.  First, Google forced me to sign up for the Blogger beta, which removed my account from that blog, and second, I've changed jobs, and DBA IQ was set up as a sounding board for the stellar DBA team led by Rob Liander at Capital IQ. &lt;br /&gt;&lt;br /&gt;I'm now at Bank of America working on the Global Credit Products team, where I'll be working on many of the same SQL development and management challenges that I did at Capital IQ and hopefully writing about the interesting ones.  I won't go into the details of why I changed positions, but I will say that I knocked 30 minutes off my daily commute!  Seriously, though, CapIQ is a great company (ahem, division of McGraw-Hill) and is full of cool and very bright people.  Everyone should read &lt;a href="http://mcfunley.com/cs/blogs/dan/default.aspx"&gt;Dan McKinley's development-focused blog&lt;/a&gt; and &lt;a href="http://dbaiq.blogspot.com"&gt;DBA IQ&lt;/a&gt;, which will hopefully continue to be updated by Rob, Mike Forman, and the other senior DBAs there.&lt;br /&gt;&lt;br /&gt;I've mostly been working on getting up to speed here so far, although I've authored and implemented a new DR strategy for my team and I've been working on performance tuning.  Stay tuned for more interesting SQL Server posts soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2021989930591302225-4205874397919231627?l=nyc-dba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nyc-dba.blogspot.com/feeds/4205874397919231627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2021989930591302225&amp;postID=4205874397919231627' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4205874397919231627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2021989930591302225/posts/default/4205874397919231627'/><link rel='alternate' type='text/html' href='http://nyc-dba.blogspot.com/2006/12/start-me-up.html' title='Start me up'/><author><name>Ira Pfeifer</name><uri>http://www.blogger.com/profile/09313712310740744659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_8yUEHkyTv1w/R4u0OcDhcpI/AAAAAAAAARo/Eppwr0QAJfQ/S220/thoughtful.jpg'/></author><thr:total>0</thr:total></entry></feed>
