I was told to implement as demonstrated below as this is how its been done before. ... this smells funny to me.
You know what smells funnier than this approach? That line of "reasoning". The old "this is how it's always been done" is simply a means of avoiding thinking about it and discussing it. And that alone should raise a red flag, even if the code is found to be the best approach. I've been told the same thing before and it was for the same sad underlying reason: that approach had been taken for an obsolete reason (such as an older version of SQL Server didn't have a particular feature, but we were using a newer version that did have that feature). Very frustrating.
Doesn't a table valued type work better here? More readable, performance, less error prone, etc...
Assuming that you are using SQL Server version 2008 or newer, then the answer is generally YES to all of that. I mean, the current code is a somewhat clever-ish approach to avoiding a string split operation. But, a TVP can be strongly-typed so no munging the int
values in the app layer into a byte[]
just so that it can be unpacked in a WHILE
loop here. A single set-based UPDATE
statement will be much better for performance than N number of UPDATE
s based on how many IDs are in that list (the current code creates, and commits) 1 transaction per each UPDATE
statement since the WHILE
loop is not wrapped in an explicit transaction. Hence, 20 IDs to update = 20 transactions in the current approach. This is part of why the single, set-based UPDATE
is more efficient.
Just be sure to implement the full-streaming approach which means: do not dump the values from a collection into a DataTable
! Doing so, which is unfortunately what you find in most examples, is a needless waste of time, memory, and CPU. Instead, create a method that implements IEnumerable
, accepts the collection of UserIDs, and returns IEnumerable<SqlDataRecord>
. Then, use that method as the "value" for the SqlParameter
that is the TVP. In that method, cycle through the collection, and per each element, call yield return;
.
I have some example code on StackOverflow in my answer to the following question:
Pass Dictionary to Stored Procedure T-SQL
Please note that I have heard, though not yet tested, that on the more recent versions of SQL Server (2014 or newer) that there might be additional performance gains by using in-memory OLTP for the User-Defined Table Type.
Also, since you mentioned this as part of a desire for "more readable code", I would suggest using meaningful parameter and variable names :-). And yes, I do realize that this is probably not your code, but just thought I would mention it. Also, I would get rid of DECLARE @tblTmp
as it isn't be used, but again, I realize that this might be a part of a larger example that you redacted.