1

I know there are quite a few other posts and articles on this but I have been searching for a solution hours now and nothing has worked for me. I have a query that generates a listing of all SQL Reporting Services (SSRS) reports listed on a given server with their associated parameters and valid values:

;WITH XMLNAMESPACES (
DEFAULT 'http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition',
'http://schemas.microsoft.com/SQLServer/reporting/reportdesigner' AS rd --ReportDefinition
)
SELECT 
   NAME as Name
   , PATH as Path
   , x.value ('@Name', 'VARCHAR(100)') AS ReportParameterName
   , x.value ('DataType[1]', 'VARCHAR(100)') AS DataType
   , x.value ('AllowBlank[1]', 'VARCHAR(50)') AS AllowBlank
   , x.value ('Prompt[1]', 'VARCHAR(100)') AS Prompt
   , x.value ('Hidden[1]', 'VARCHAR(100)') AS Hidden
   , x.value ('data(DefaultValue/Values/Value)[1]', 'VARCHAR(100)') AS DefaultValue
   , y.value ('Value[1]','VARCHAR(100)') AS VaildValues
   , y.value ('Label[1]','VARCHAR(100)') AS VaildValuesLabel
FROM (
   SELECT  PATH
           , NAME
           , CAST(CAST(content AS VARBINARY(MAX)) AS XML) AS ReportXML 
   FROM Catalog 
   WHERE CONTENT IS NOT NULL AND TYPE = 2
   ) A
CROSS APPLY ReportXML.nodes('/Report/ReportParameters/ReportParameter') R(x)
OUTER APPLY R.x.nodes('ValidValues/ParameterValues/ParameterValue') P(y) 
ORDER BY NAME

This query takes about 4 and a half minutes to run in SSMS. I want to take the results of this query in the form of a C# DataTable, to use as the parameter for a stored procedure that runs on a different server. Unfortunately when running the SQL script through my C# code the takes at least 3 hours to run, assuming it would ever finish at all (gave up after 3 hours).

I know the SET options are different when running from SSMS and from application so, I tried to manually make the settings the same as they are in SSMS. Here is a snippet of the code:

DataSet ds = new DataSet();
string SQL_Script = File.ReadAllText(runRdlQueryFilePath);
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
        {

            SqlDataAdapter da = new SqlDataAdapter();
            SqlCommand cmd = conn.CreateCommand();
            cmd.CommandText = SQL_Script;
            da.SelectCommand = cmd;
            conn.Open();
            Console.WriteLine("setting QUOTED_IDENTIFIER on...");
            using (SqlCommand comm = new SqlCommand("SET QUOTED_IDENTIFIER ON", conn))
            {
                comm.ExecuteNonQuery();
            }
            Console.WriteLine("setting ANSI_NULLS on...");
            using (SqlCommand comm = new SqlCommand("SET ANSI_NULLS ON", conn))
            {
                comm.ExecuteNonQuery();
            }
            Console.WriteLine("setting ARITHABORT on...");
            using (SqlCommand comm = new SqlCommand("SET ARITHABORT ON", conn))
            {
                comm.ExecuteNonQuery();
            }
            //this one will not run for some reason but I think it is the default when running from C# client anyways
            //using (SqlCommand comm = new SqlCommand("SET CONCAT_NULL_YEILDS_NULL ON", conn))
            //{
            //    comm.ExecuteNonQuery();
            //}
            Console.WriteLine("setting  XACT_ABORT on...");
            using (SqlCommand comm = new SqlCommand("SET XACT_ABORT ON", conn))
            {
                comm.ExecuteNonQuery();
            }
            Console.WriteLine("setting LOCK_TIMEOUT -1...");
            using (SqlCommand comm = new SqlCommand("SET LOCK_TIMEOUT -1", conn))
            {
                comm.ExecuteNonQuery();
            }
            Console.WriteLine("Executing get rdl info query, this may take some time..."); 

            da.Fill(ds);

            //I have also tried this method of filling the DataSet...
            /*
            Server server = new Server(new ServerConnection(conn));
                //bool queryRan = true;
                //read sql file
                string script = File.ReadAllText(runRdlQueryFilePath);
            Console.WriteLine("Executing get rdl info query, this may take some time...");
            ds = server.ConnectionContext.ExecuteWithResults(script);
            */
        }

I don't see how parameter sniffing would be an issue here as the query takes no parameters, but I tried putting an

OPTION (RECOMPILE)

on my query just for fun and had no success with this either. Unfortunately I am not the owner of this database and do not have permissions to create a stored procedure on it, so I have not tried converting the query to a stored procedure.

Any ideas what else could be stopping the query from executing efficiently in the application?

Thanks for any help!

David Browne - Microsoft
  • 80,331
  • 6
  • 39
  • 67
  • I don't know why the downvotes, this is a perfectly legitimate question... – RBarryYoung Jul 09 '18 at 21:30
  • Can you get the Query Plan in SSMS and post it here? – RBarryYoung Jul 09 '18 at 21:31
  • 1
    Don't set all those options on different commands... do it all at once. And have you tried doing an ExecuteQuery instead of a da.Fill()? Have you run a SQL Trace to see exactly what SQL is going to the server, and comparing with what you have in SSMS? – pmbAustin Jul 09 '18 at 21:31
  • I believe that the correct settings are: `SET NUMERIC_ROUNDABORT OFF;` and `SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS ON; ` – RBarryYoung Jul 09 '18 at 21:43
  • Also, how many rows are returned? – RBarryYoung Jul 09 '18 at 21:47
  • What is the **exact** value of `SQL_Script`? – mjwills Jul 10 '18 at 01:01
  • With regards to SET options and parameter sniffing, this is what happens: 1. You submit the query from C# with certain default C# SET options and a query plan is generated; 2. You submit the query from SSMS with certain default SET options (that happen to be the different to the C# ones) and a _different_ query plan is generated. Note no parameters here - the point is that SET options are different so it thinks it's a different query so it generates a different query plan. – Nick.Mc Jul 10 '18 at 01:17
  • As @pmbAustin said, setting those options inside different `using` is probably not doing what you think it is. They should be all in the same `using`. But it doesn't matter because the library probably just runs it's SET's afterwards and overwrites yours anyway. So what you need to do is 1. Capture query plans for both queries and confirm they are different; 2. Focus in getting `OPTION (RECOMPILE)` right – Nick.Mc Jul 10 '18 at 01:19
  • @RBarryYoung Apologies for the late reply posted late in the day and it looked like this was getting downdoted to oblivion (I wasn't sure why either) so I didn't hang around for replies. Anyways, regarding the query execution plan unfortunately for some reason I do not have "SHOWPLAN permissions" on that server but I'll see if I can track down the DBAs and get one or permissions for this. The query returns about 4400 rows. I am trying your settings now and it does not appear to be working unfortunately. – user9265172 Jul 10 '18 at 13:51
  • There's not a lot that we can do without more information. I'd recommend talking to the DBA and seeing if they can help you get the query plan for both instances. – RBarryYoung Jul 10 '18 at 13:55
  • @pmbAustin that format was based on [this anwser](https://stackoverflow.com/a/2736682/9265172). I seperated it into different blocks since it was having an issue with SET CONCAT_NULL_YIELDS_NULL – user9265172 Jul 10 '18 at 13:56
  • @RBarryYoung Yes it looks like that is the only option since I am also not permitted to do an SQL trace as was also suggested. I will do that and come back with more info. thanks. – user9265172 Jul 10 '18 at 14:01
  • Executing as Non Query also does not seem to work. – user9265172 Jul 10 '18 at 14:10

0 Answers0