0

Using .NET 4.0, I have defined the following sqlcommand. When I execute the sqlcommand multiple times consecutively without making any changes, SQL Server refuses to cache the query plan.

string[] colors = new string[] { "red", "blue", "yellow", "green" };
string cmdText = "SELECT * FROM ColoredProducts WHERE Color IN ({0})";

string[] paramNames = tags.Select(
    (s, i) => "@color" + i.ToString()
).ToArray();

string inClause = string.Join(",", paramNames);
using (SqlCommand cmd = new SqlCommand(string.Format(cmdText, inClause))) {
    for(int i = 0; i < paramNames.Length; i++) {
       cmd.Parameters.AddWithValue(paramNames[i], tags[i]);
    }
    //Execute query here
}

I know it's refusing the cache the plan because the following query was running at a fraction of the time after consecutive runs:

string[] colors = new string[] { "red", "blue", "yellow", "green" };
string cmdText = "SELECT * FROM ColoredProducts WHERE Color IN ({0})";

string inClause = string.Join(",", colors);
using (SqlCommand cmd = new SqlCommand(string.Format(cmdText, inClause))) {
       //Execute query here
}

In my actual test case the param list is fixed at a size of exactly 2000. The scenario I am attempting to optimize is selecting a specific set of 2000 records from a very large table. I would like for the query to be as fast as possible so I really want it to cached.

Sleepy post Edit: The question is, why wouldn't this plan get cached? And yes, I have confirmed that the query is not in the cache using sys.dm_exec_cached_plans and sys.dm_exec_sql_test.

4

1 回答 1

1

这是一个使用表值参数的想法。请让我们知道这种方法是否比您的大字符串执行得更好。还有其他想法,但这是最接近将您的颜色集视为数组的方法。

在 SQL Server 中:

CREATE TYPE dbo.Colors AS TABLE
(
  Color VARCHAR(32) -- be precise here! Match ColoredProducts.Color
     PRIMARY KEY
);
GO

CREATE PROCEDURE dbo.MatchColors
  @colors AS dbo.Colors READONLY
AS
BEGIN
  SET NOCOUNT ON;

  SELECT cp.* -- use actual column names please!
  FROM dbo.ColoredProducts AS cp -- always use schema prefix
  INNER JOIN @colors AS c
  ON cp.Color = c.Color; 
END
GO

现在在 C# 中:

DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("Color"));

tvp.Rows.Add("red"); 
tvp.Rows.Add("blue"); 
tvp.Rows.Add("yellow"); 
tvp.Rows.Add("green"); 
// ...

using (connectionObject)
{
    SqlCommand cmd = new SqlCommand("dbo.MatchColors", connectionObject);
    cmd.CommandType = CommandType.StoredProcedure;
    SqlParameter tvparam = cmd.Parameters.AddWithValue("@colors", tvp);
    tvparam.SqlDbType = SqlDbType.Structured;
    // execute query here
}

我几乎可以保证这将比IN具有大量参数的列表执行得更好,而不管 C# 代码中实际字符串的长度如何。

于 2012-05-01T04:11:57.453 回答