2

I have a stored procedure that dynamically generates a table to hold staging data for imports. This routine was running fine until Wednesday. I have tracked this down to one particular area. Code that's causing an issue is:

DECLARE @strSQL NVARCHAR(MAX) = N'';

SELECT  @strSQL = @strSQL + N',[' + CustomerField + N'] NVARCHAR(MAX)' + CHAR(10)
  FROM  dbo.WebServices
 WHERE  CallType = 'customer'
   AND  IsPrimaryTable = 1
   AND  Source = 'clientName'
 ORDER BY TagOrder;

SET @strSQL = STUFF(@strSQL, 1, 1, 'CREATE TABLE ' + 'TableName' + CHAR(10) + '(')+ N')';

PRINT @strSQL

NB. Table its pulling from holds a list of columns and the data hasn't changed either. There are about 34 rows of data with no special characters, and it isn't exposed to the clients.

This gives me an output of:

CREATE TABLE TableName
([CUSACNR2] NVARCHAR(MAX)
)

Running this on exactly the same data, even in the same window on SSMS, with an additional TOP filter gives me the results I was expecting i.e.

DECLARE @strSQL NVARCHAR(MAX) = N'';

SELECT  TOP (99999) @strSQL = @strSQL + N',[' + CustomerField + N'] NVARCHAR(MAX)' + CHAR(10)
  FROM  dbo.WebServices
 WHERE  CallType = 'customer'
   AND  IsPrimaryTable = 1
   AND  Source = 'clientName'
 ORDER BY TagOrder;

SET @strSQL = STUFF(@strSQL, 1, 1, 'CREATE TABLE ' + 'TableName' + CHAR(10) + '(')+ N')';

PRINT @strSQL

Generates the dynamic SQL:

CREATE TABLE TableName
([TAG] NVARCHAR(MAX)
,[CUSACNR] NVARCHAR(MAX)
.
.
.
,[SHIPPING_POSTAL_CODE] NVARCHAR(MAX)
,[CUSACNR2] NVARCHAR(MAX)
)
  • Specific column names removed for security

While I have tracked this down in one specific stored proc, we use this technique for building dynamic SQL a lot and I am seeing errors popping up in multiple places. I'm assuming that something has changed on the server as this has started happening in multiple databases at one time.

Does anyone know of anything that may have caused this issue? Its a legacy system that has been running fine for a long time and re-coding every instance of this type of activity is not an option.

GSerg
  • 76,472
  • 17
  • 159
  • 346
Matthew Baker
  • 2,637
  • 4
  • 24
  • 49
  • 1
    `I am seeing errors popping up in multiple places` - what errors and in which places? – GSerg Feb 15 '19 at 09:42
  • 1
    do you have any specific error message? could the permission of the user accessing the db/stored proc or the stored proc itself have changed? what work was done on/just before wednesday? can you check back to see if anything looks like it could have caused this? do you have a DB backup from Tuesday you could restore to another instance to run this code against? – scgough Feb 15 '19 at 09:42
  • 2
    On a side note, `N',[' + CustomerField + N']` is [utterly wrong](https://stackoverflow.com/q/332365/11683) and should be replaced with `N',' + quotename(CustomerField, '[')`. – GSerg Feb 15 '19 at 09:43
  • When I say seeing errors, I mean that the code is not functioning as expected. Temporary tables are being generated only with the last column which then forms logical errors. The code itself runs, its the output that is problematic. – Matthew Baker Feb 15 '19 at 09:45
  • 1
    Have you tried running `SELECT CustomerField FROM dbo.WebServices WHERE CallType = 'customer' AND IsPrimaryTable = 1 AND Source = 'clientName' ORDER BY TagOrder;`? – GSerg Feb 15 '19 at 09:50
  • Yeah, The select works fine, its only when concatenating it into the dynamic sql. And it works fine if I add the TOP (99999), which to me should make no difference at all. – Matthew Baker Feb 15 '19 at 09:53
  • 1
    Does the same happen [with `for xml path('')`](https://stackoverflow.com/q/35148472/11683) and without the `top()`? Does the same happen with `isnull(CustomerField)`? How do you view the result? – GSerg Feb 15 '19 at 10:00
  • 2
    *This routine was running fine until Wednesday.* - Wednesday is 13 Feb. Date conversion related problems? :) – Alexander Volok Feb 15 '19 at 10:04
  • No dates involved here, but good suggestion. – Matthew Baker Feb 15 '19 at 10:06
  • ISNULL makes no difference. for_xml_path('') works exactly as I'd expect with or without the TOP. Problem will be finding every instance of this. Need to identify root cause really. – Matthew Baker Feb 15 '19 at 10:08
  • 1
    What happens if you do not do the `stuff()` in the end? What happens if you omit `order by`? – GSerg Feb 15 '19 at 10:20
  • Stuff doesn't help, however removing the sort order did. The problem is that we need the sort order. Not so much here, but we have insert commands that we build dynamically too in other procedures and they are also failing. – Matthew Baker Feb 15 '19 at 10:24
  • Really need to identify whats causing the existing code to fail - rewriting all of it isn't an option. – Matthew Baker Feb 15 '19 at 10:25
  • 1
    What is your `@@version`? – GSerg Feb 15 '19 at 10:33
  • Microsoft SQL Server 2016 (SP1) (KB3182545) - 13.0.4001.0 (X64) Oct 28 2016 18:17:30 Copyright (c) Microsoft Corporation Web Edition (64-bit) on Windows Server 2016 Standard 6.3 (Build 14393: ) – Matthew Baker Feb 15 '19 at 10:34
  • 1
    Please try installing first [Service Pack 2](https://www.microsoft.com/en-us/download/details.aspx?id=56836), then [SP2 CU5](https://www.microsoft.com/en-us/download/details.aspx?id=56975). – GSerg Feb 15 '19 at 10:40
  • 1
    Has anything collation related been altered - just thinking if the connection settings around the string comparison have changed to case sensitive, which alters the string comparison results in the select statement. – Andrew Feb 15 '19 at 10:42
  • 1
    Hi Andrew. Not that I can see. Collation is our standard both at server and database level. Also a collation change wouldn't explain why I get the expected results just by adding the "TOP" condition. – Matthew Baker Feb 15 '19 at 10:47
  • 1
    Restore a backup to the same server and see if the issue occurs on the database of days gone by. If not, pull out the differencing tools and start comparing. This technique (`SELECT @var = @var + ... ORDER BY`) isn't stable to begin with, but you may have gotten lucky with the optimizer picking the "correct" plans based on past indexes, estimates and statistics. You can also try [sp_Blitz](https://www.brentozar.com/blitz/) to check if any server-wide settings have been "helpfully" changed from the defaults. `MAXDOP`, optimize for ad-hoc queries, anything that can influence plan generation. – Jeroen Mostert Feb 15 '19 at 11:46
  • 1
    Oh, and (doy) you should compare the [actual execution plans](https://www.brentozar.com/pastetheplan/) of the working vs. the non-working setup. Specifically, look at changed order of operators, introduced or removed parallelism, that sort of thing. Different results mean different execution, either through different plans or because the existing ones are executed differently (the latter only really happens with inherently non-deterministic plans that use parallelism, if the actual table data doesn't change). – Jeroen Mostert Feb 15 '19 at 11:49

1 Answers1

1

I have found the answer. Sort of. I now know what had changed, so I've been able to correct it, but it should not have made any difference.

There was an index on the table that was causing the issue. Before you say that shouldn't make any difference, and you're right it shouldn't, I've managed to reliably solve and reproduce the problem by dropping and recreating the index.

So this isn't a fragmentation issue, it's not a clustered index, and the execution plan doesn't search by this index anyway.

CREATE NONCLUSTERED INDEX [idx_ntindex] ON [dbo].[WebServices] ([Source], [CallType], [SecurityKey])

GO

DECLARE @strSQL NVARCHAR(MAX) = N'';

SELECT  @strSQL = @strSQL + N',[' + ISNULL(CustomerField,'') + N'] NVARCHAR(MAX)' + CHAR(10)
  FROM  dbo.WebServices
 WHERE  CallType = 'customer'
   AND  IsPrimaryTable = 1
   AND  Source = 'clientName'
  ORDER BY TagOrder;

SET @strSQL = STUFF(@strSQL, 1, 1, 'CREATE TABLE ' + 'TableName' + CHAR(10) + '(') + N')';

PRINT @strSQL;

GO

DROP INDEX idx_ntindex ON dbo.WebServices

DECLARE @strSQL NVARCHAR(MAX) = N'';

SELECT  @strSQL = @strSQL + N',[' + ISNULL(CustomerField,'') + N'] NVARCHAR(MAX)' + CHAR(10)
  FROM  dbo.WebServices
 WHERE  CallType = 'customer'
   AND  IsPrimaryTable = 1
   AND  Source = 'clientName'
  ORDER BY TagOrder;

SET @strSQL = STUFF(@strSQL, 1, 1, 'CREATE TABLE ' + 'TableName' + CHAR(10) + '(') + N')';

PRINT @strSQL;

Gives me the results

CREATE TABLE TableName
([CUSACNR2] NVARCHAR(MAX)
)

CREATE TABLE TableName
([TAG] NVARCHAR(MAX)
,[CUSACNR] NVARCHAR(MAX)
,[DDAYS] NVARCHAR(MAX)
.
.
.
,[SHIPPING_POSTAL_CODE] NVARCHAR(MAX)
,[CUSACNR2] NVARCHAR(MAX)
)

If anyone knows WHY this is the case then please let me know. I found it but it doesn't make any sense to me.

Thanks for the help all. +1's for all the support, each suggestion got me a little closer.

Matthew Baker
  • 2,637
  • 4
  • 24
  • 49
  • It would probably have been better to post this at [dba](https://dba.stackexchange.com). – GSerg Feb 15 '19 at 14:46