【发布时间】:2017-03-14 20:20:53
【问题描述】:
我使用以下 C# 代码将 ID 列表发送到 SQL Server 2012。它过滤 mytable 的列 ID 并返回前 50 个匹配的 ID。
实际上执行查询大约需要 180 毫秒。数据库是本地的。我想知道是否有一些方法可以提高性能。我注意到性能与发送到 SQL 服务器的 id 数量直接相关,而不是与表中的实际记录数相关。如果我只发送一千条记录,它会非常快(
用户定义的表int_list_type和mytable是这样定义的:
CREATE TABLE mytable (Id int NOT NULL PRIMARY KEY CLUSTERED)
CREATE TYPE int_list_type AS TABLE(Id int NOT NULL PRIMARY KEY CLUSTERED)
C#代码:
static void Main()
{
List<int> idsToSend = Enumerable.Range(0, 200000).ToList();
List<int> idsResult = new List<int>();
Stopwatch sw = Stopwatch.StartNew();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand(@" SELECT TOP 50 t.Id FROM MyTable t
INNER JOIN @ids lt ON t.Id = lt.Id",
connection);
command.Parameters.Add(new SqlParameter("@ids", SqlDbType.Structured)
{
TypeName = "int_list_type",
Direction = ParameterDirection.Input,
Value = GetSqlDataRecords(idsToSend)
});
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
idsResult.Add(reader.GetInt32(0));
}
}
Console.WriteLine(sw.Elasped);
}
private static IEnumerable<SqlDataRecord> GetSqlDataRecords(IEnumerable<int> values)
{
SqlMetaData[] metaData = { new SqlMetaData("Id", SqlDbType.Int) };
foreach (int value in values)
{
SqlDataRecord rec = new SqlDataRecord(metaData);
rec.SetInt32(0, value);
yield return rec;
}
}
编辑:根据 Fabio 的建议,我查看了 GetSqlDataRecords() 方法,这是大部分时间都需要的。我是这样单独测试的:
Stopwatch sw = Stopwatch.StartNew();
GetSqlDataRecords(listOfIfs).ToList();
Console.WriteLine(sw.Elapsed);
【问题讨论】:
-
旁注:使用
TOP x没有ORDER BYcaluse 意味着您获得 x 条记录,但并不意味着您获得 first x 条记录 - 数据库表是本质上是无序的,因此如果没有ORDER BY子句,就无法保证SELECT语句返回的行的顺序。 -
您是否检查过什么是实际的“瓶颈” - 数据库或
GetSqlDataRecords中的循环? -
要获得更准确的测量结果,您需要在 connection.open() 语句之后启动秒表。打开连接总是很慢。理想情况下,您需要缓存它或使用连接池。此外,在输出经过时间之前停止秒表。写入控制台也很慢,因此在执行此操作之前需要停止。
-
@jason.kaisersmith 是的,它提高了精度,但在 OP 中说,这些不是瓶颈。
-
您可以尝试
SELECT TOP 50 t.Id FROM MyTable t INNER JOIN @ids lt ON t.Id = lt.Id OPTION (RECOMPILE),以便它可以考虑表变量中的行数。
标签: c# sql-server performance primary-key bulk