我目前正在尝试找出从 C# 读取 SQL Server 数据的最有效方法。
我对我得到的结果之一感到非常惊讶。
1)
watch.Restart();
while (reader.Read())
{
lst.Add(new { n = reader.GetInt64(0), a = reader.GetString(1), b = reader.GetString(2) });
}
watch.Stop();
2)
watch.Restart();
while (reader.Read())
{
lst.Add(new { n = reader[0], a = reader[1], b = reader[2] });
}
watch.Stop();
由于某种原因,第一个循环比第二个循环执行得更快。
我读过铸造是一项耗时的操作,所以我想看看它要花多少钱,但在这里,我不明白。
你知道这是为什么吗?
编辑:完整代码
class Program
{
private class Measure
{
public TimeSpan TimeCommand;
public TimeSpan TimeExecute;
public Measure()
{
this.TimeCommand = new TimeSpan(0);
this.TimeExecute = new TimeSpan(0);
}
}
private static void Write(string str)
{
Console.Write(".");
// Console.Write(str);
}
private static void WriteLine(string str)
{
Console.Write(".");
// Console.WriteLine(str);
}
static void Main(string[] args)
{
var measures = new Dictionary<string, Measure>();
List<Action> actions = new List<Action>();
Stopwatch watch;
SqlCommand com;
List<object> lst;
DataTable table;
SqlDataReader reader;
actions.Add(() =>
{
lst = new List<object>();
#region DataTable cast
var line = "DataTable cast";
Measure measure;
if (!measures.TryGetValue(line, out measure))
{
measures.Add(line, (measure = new Measure()));
}
com = GetCommand();
watch = Stopwatch.StartNew();
Write(line + "... ");
table = new DataTable();
new SqlDataAdapter(com).Fill(table);
watch.Stop();
measure.TimeCommand += watch.Elapsed;
Write(watch.Elapsed.ToString(@"mm\:ss\.ffff") + "...");
lst = new List<object>();
watch.Restart();
foreach (DataRow dr in table.Rows)
{
lst.Add(new { n = (long)dr["n"], a = (string)dr["a"], b = (string)dr["b"] });
}
watch.Stop();
measure.TimeExecute += watch.Elapsed;
WriteLine(watch.Elapsed.ToString(@"mm\:ss\.ffff") + " " + lst.Count.ToString());
#endregion
});
actions.Add(() =>
{
lst = new List<object>();
#region DataTable cast
var line = "DataTable field";
Measure measure;
if (!measures.TryGetValue(line, out measure))
{
measures.Add(line, (measure = new Measure()));
}
com = GetCommand();
watch = Stopwatch.StartNew();
Write(line + "... ");
table = new DataTable();
new SqlDataAdapter(com).Fill(table);
watch.Stop();
measure.TimeCommand += watch.Elapsed;
Write(watch.Elapsed.ToString(@"mm\:ss\.ffff") + "...");
lst = new List<object>();
watch.Restart();
foreach (DataRow dr in table.Rows)
{
lst.Add(new { n = dr.Field<long>("n"), a = dr.Field<string>("a"), b = dr.Field<string>("b") });
}
watch.Stop();
measure.TimeExecute += watch.Elapsed;
WriteLine(watch.Elapsed.ToString(@"mm\:ss\.ffff") + " " + lst.Count.ToString());
#endregion
});
actions.Add(() =>
{
lst = new List<object>();
#region Reader ordinal
var line = "Reader ordinal no cast";
Measure measure;
if (!measures.TryGetValue(line, out measure))
{
measures.Add(line, (measure = new Measure()));
}
com = GetCommand();
watch = Stopwatch.StartNew();
Write(line + "... ");
com.Connection.Open();
using (reader = com.ExecuteReader())
{
watch.Stop();
measure.TimeCommand += watch.Elapsed;
Write(watch.Elapsed.ToString(@"mm\:ss\.ffff") + "...");
lst = new List<object>();
watch.Restart();
while(reader.Read())
{
lst.Add(new { n = reader.GetInt64(0), a = reader.GetString(1), b = reader.GetString(2) });
}
watch.Stop();
measure.TimeExecute += watch.Elapsed;
WriteLine(watch.Elapsed.ToString(@"mm\:ss\.ffff") + " " + lst.Count.ToString());
}
com.Connection.Close();
#endregion
});
actions.Add(() =>
{
lst = new List<object>();
#region Reader ordinal
var line = "Reader ordinal no cast try";
Measure measure;
if (!measures.TryGetValue(line, out measure))
{
measures.Add(line, (measure = new Measure()));
}
com = GetCommand();
watch = Stopwatch.StartNew();
Write(line + "... ");
com.Connection.Open();
try
{
using (reader = com.ExecuteReader())
{
watch.Stop();
measure.TimeCommand += watch.Elapsed;
Write(watch.Elapsed.ToString(@"mm\:ss\.ffff") + "...");
lst = new List<object>();
watch.Restart();
while (reader.Read())
{
lst.Add(new { n = reader.GetInt64(0), a = reader.GetString(1), b = reader.GetString(2) });
}
watch.Stop();
measure.TimeExecute += watch.Elapsed;
WriteLine(watch.Elapsed.ToString(@"mm\:ss\.ffff") + " " + lst.Count.ToString());
}
}
finally
{
com.Connection.Close();
}
#endregion
});
actions.Add(() =>
{
lst = new List<object>();
#region Reader ordinal
var line = "Reader ordinal cast";
Measure measure;
if (!measures.TryGetValue(line, out measure))
{
measures.Add(line, (measure = new Measure()));
}
com = GetCommand();
watch = Stopwatch.StartNew();
Write(line + "... ");
com.Connection.Open();
using (reader = com.ExecuteReader())
{
watch.Stop();
measure.TimeCommand += watch.Elapsed;
Write(watch.Elapsed.ToString(@"mm\:ss\.ffff") + "...");
lst = new List<object>();
watch.Restart();
while (reader.Read())
{
lst.Add(new { n = (long)reader[0], a = (string)reader[1], b = (string)reader[2] });
}
watch.Stop();
measure.TimeExecute += watch.Elapsed;
WriteLine(watch.Elapsed.ToString(@"mm\:ss\.ffff") + " " + lst.Count.ToString());
}
com.Connection.Close();
#endregion
});
actions.Add(() =>
{
lst = new List<object>();
#region Reader ordinal
var line = "Reader ordinal no type";
Measure measure;
if (!measures.TryGetValue(line, out measure))
{
measures.Add(line, (measure = new Measure()));
}
com = GetCommand();
watch = Stopwatch.StartNew();
Write(line + "... ");
com.Connection.Open();
using (reader = com.ExecuteReader())
{
watch.Stop();
measure.TimeCommand += watch.Elapsed;
Write(watch.Elapsed.ToString(@"mm\:ss\.ffff") + "...");
lst = new List<object>();
watch.Restart();
while (reader.Read())
{
lst.Add(new { n = reader[0], a = reader[1], b = reader[2] });
}
watch.Stop();
measure.TimeExecute += watch.Elapsed;
WriteLine(watch.Elapsed.ToString(@"mm\:ss\.ffff") + " " + lst.Count.ToString());
}
com.Connection.Close();
#endregion
});
for (int x = 0; x < 10; x++)
{
var range = Enumerable.Range(0, actions.Count).OrderBy(elt => Guid.NewGuid());
foreach(var i in range)
{
var action = actions[i];
action();
}
}
Console.WriteLine();
var keys = measures.Keys.OrderBy(s => s);
foreach (var k in keys)
{
Console.WriteLine(String.Format(
@"{0} - Command: {1:mm\:ss\.ffff} Execute: {2:mm\:ss\.ffff}"
, k
, measures[k].TimeCommand
, measures[k].TimeExecute
));
}
Console.ReadKey();
}
static SqlCommand GetCommand()
{
return new SqlCommand()
{
Connection = new SqlConnection("server=localhost;uid=xxx;pwd=xxx;database=xxx")
, CommandType = System.Data.CommandType.Text
, CommandText = @"
SELECT
n
, 'a' AS a
, 'b' AS b
FROM dbo.v_VIRTUAL_NUMBERS AS N
WHERE N < 100000
"
};
}
}
如果要运行代码,dbo.v_VIRTUAL_NUMBERS 可以是任何计数表。