使用.NET 4.0,我已经定义了以下sqlcommand。当我连续多次执行sqlcommand而不进行任何更改时,SQL Server拒绝缓存查询计划。
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
}
我知道它拒绝缓存计划,因为以下查询在连续运行后的一小部分时间内运行:
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
}
在我的实际测试用例中,参数列表固定为2000的大小。我试图优化的场景是从一个非常大的表中选择一组特定的2000条记录。我希望查询尽可能快,所以我真的希望它能够缓存。
困了帖子编辑: 问题是,为什么这个计划不会被缓存?是的,我已经使用sys.dm_exec_cached_plans和sys.dm_exec_sql_test确认查询不在缓存中。
答案 0 :(得分: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#代码中实际字符串的长度如何。