0

我目前正在尝试找出从 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 可以是任何计数表。

4

0 回答 0