Does the length of the CommandText of an SqlCommand make a difference? I’m not talking about thousands of characters either. Here’s what I have:
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
for (int i=0; i<1000; ++i)
{
string name = i.ToString() + "Bob" + i.ToString();
string email = i.ToString() + "Jim" + i.ToString();
// etc...
cmd.Parameters.Clear();
cmd.Parameters.Add(new SqlParameter("@name", name));
cmd.Parameters.Add(new SqlParameter("@country", country));
DateTime cmdStart = DateTime.Now;
cmd.ExecuteNonQuery();
DateTime cmdEnd = DateTime.Now;
TimeSpan len = cmdEnd - cmdStart;
}
If I use the following sql, the first iteration takes .5 seconds. The second takes 1.1 seconds. The third takes 3.3 seconds. And so on until it just throws for a timeout.
string sql =
"INSERT INTO Test " +
" ([name] " +
" ,[email] " +
" ,[country] " +
" ,[comment] " +
" ,[date] " +
" ,[key_v0] " +
" ,[key_v1] " +
" ,[expires_v1] " +
" ,[expires_v2] " +
" ) " +
" VALUES " +
" (@name " +
" ,@email " +
" ,@country " +
" ,' ' " +
" ,@date " +
" ,@key_v0 " +
" ,@key_v1 " +
" ,@expires_v1 " +
" ,@expires_v2 " +
" )";
However, if I use the following sql, the entire loop is executed in under a second.
string sql =
"INSERT INTO Test " +
"([name] " +
",[email] " +
",[country] " +
",[comment] " +
",[date] " +
",[key_v0] " +
",[key_v1] " +
",[expires_v1] " +
",[expires_v2] " +
") " +
"VALUES " +
"(@name " +
",@email " +
",@country " +
",' ' " +
",@date " +
",@key_v0 " +
",@key_v1 " +
",@expires_v1 " +
",@expires_v2 " +
")";
The only difference is the whitespace. Removing the whitespace brought the total character count from 428 to 203. I have been unable to locate anything referencing the length of CommandText except references to 4k and 8k limits. I’m nowhere near that.
I have run both versions with the profiler running and it the duration is under 10ms for all calls. The delay seems to be happening from when the command is complete inside the SQL engine until ExecuteNonQuery returns.
I know that there are alternative ways to do this. I’m not asking about better ways to do this. I’m asking about the source of the slowdown.
UPDATE:
As a test, I added spaces to the end of the query. As soon as I got above 400ish characters total, it slowed down. Interestingly, at 414 characters, the first 99 inserts are fast. At 415 characters, the first 9 inserts are fast. Since I am changing some of the strings based on the iteration number, this kinda makes sense. e.g. The 10th insert is a little longer than the 9th and the 100th insert is a little longer than the 99th.
While I kinda understand that longer inserts should take longer, I can’t understand the clear division between fast and slow and the sheer magnitude of the difference. I also don’t understand why the time taken increases.
UPDATE 2:
(Additional information in response to Peter Oehlert’s answer):
The entire database is clean. There are no other tables and the test table is dropped and recreated for each run. There are no indexes, triggers or foreign keys. There is an ‘id’ column that is a primary key.
This is code pulled from a console app written specifically to troubleshoot this problem. It only includes the necessary code to repro this behavior.
(Aditional profiler information):
When running the SQL profiler, there is a column called TextData that shows what the command and data are. An example is this:
exec sp_executesql N'INSERT INTO Test ([name] ,[email] ,[country] ,[comment] ,[date] ,[key_v0] ,[key_v1] ,[expires_v1] ,[expires_v2] ) VALUES (@name ,@email ,@country ,'' '' ,@date ,@key_v0 ,@key_v1 ,@expires_v1 ,@expires_v2 ) ',N'@name nvarchar(4),@country nvarchar(2),@email nvarchar(3),@date datetime,@key_v0 nvarchar(4000),@key_v1 nvarchar(4000),@expires_v1 datetime,@expires_v2 datetime',@name=N'9Bob',@country=N'us',@email=N'Jim',@date='2009-08-28 15:35:36.5770000',@key_v0=N'',@key_v1=N'',@expires_v1='2009-08-28 15:35:36.5770000',@expires_v2='2009-08-28 15:35:36.5770000'
That line is 796 characters long and runs fast. Changing the name from ‘9Bob’ to ’10Bob’ results in a slow insert. Neither 796, nor 797 seem like a significant numbers. Removing the exec sp_executesql portion means lengths of 777 and 778. They don’t seem significant either.
I’m stumped.
Update:
Posted trace here: http://www.jere.us/WierdInserts.trc
Well, I don’t have a direct answer but here is how I would approach the problem.
SQL
If it’s the database then I would look at a few things: everyone is harping on string concatenation issues which while true will likely make up less than 5 ms of your timing. I also would discount the spaces as being the source of the issue. Again it will make a small difference but will not account for the degredation that you describe. You’re looking for something that will have this progression (0.5, 1.1, 3.3).
I would look in particular at what indexes you’ve defined on this table, what constraints/ triggers are on this table, and how many foreign key relationships are present. Additionally I would pull out the queries that are executing slowly and run them in query manager (sql enterprise manager).
The final thing I might investigate is whether there is a bad cache plan introducing issues with some data dependant feature. This would only be valid if you had some interesting triggers that use a piece of your data or certain types of index updates. You can look at this by calling DBCC FREEPROCCACHE in between calls to your insert statement and see if it makes a difference. This command will clear the plan cache forcing sql to regenerate a new execution plan for your query.
Client
If it is the client then you need to determine what in your code is causing the issue. If you have a performance tracing tool (like visual studio performance analyzer) which will instrument your code I would use that as it will VERY quickly tell you precisely what is taking up so much time.
If you don’t have that option then start by pulling out your code into a new console app with the smallest possible set of contingencies and see if you can repro the behavior. You’re looking for whatever might be the cause of the progression you’re seeing.