C#从数据库缓慢加载并外推到对象中

时间:2011-05-02 08:47:14

标签: c# .net object

好的,所以我正在努力加快加载服务器所需的时间。主要是从数据库中预加载用户帐户,并将它们添加到每个包含13个变量的播放器对象列表中。

我已经决定第一步是查看系统的哪些部分花费的时间最长,因此我设置DateTime变量来计算每段代码执行的毫秒数。

我们在数据库中有大约4万个帐户,它们几乎立即加载到一个字符串列表中,然后我们将它们推断到它们的变量中,这不是最有效的方法,但速度很快,它既有效又没有错误。

无论如何,将4万个帐户外推到他们的后续对象中需要大约4分钟,设置变量并将对象添加到预加载数据列表中。

我在每个变量设置周围添加了DateTime变量,然后确定了执行时间,只有一个问题,所有数字都是0,我假设我搞砸了我的代码,所以我在几个不同的地方测试了它,它有效。

所以,现在我有点难过,试图找出所有时间和CPU周期的去向。

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

我正在测试初始对象创建,13个变量,将对象添加到列表中,然后输出总时间。这不是准确的,只是为了帮助我理解我需要改变的地方,我对40k的0行感到有点不高兴

有什么我想念的吗?据我所知,加载这些数据不应超过30秒(加上循环本身的成本)。

DateTime是不正确的?或者我在某个地方陷入困境,或者......

我很感激您对此有任何见解。

感谢您的时间:

P.S。如果你想看到整个代码,就是这样:

int pcounti = 0;
current.Text = "Pre-Loading Players."; bar.Value = 35;
List<string[]> p1 = SDB.get("Select * from players");
if (p1 != null)
{
    int dbplayercount = p1.Count;
    //REMOVE ME
    List<string> tolog = new List<string>();
    foreach (string[] s in p1)
    {
        // Check if this user already has a PDB
        try
        {
            PDB temppdb = PDB.find(s[1].Trim().ToLower());
            if (temppdb != null)
            {
                Console.WriteLine("Deleting");
                SDB.donow("DELETE FROM players WHERE username = '" + s[1] + "' AND UID != " + temppdb.UID);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Error:");
            Console.WriteLine(e.Message);
            Console.WriteLine(e.StackTrace);
        }

        // Generate PDB
        try
        {
            //We need the database to be all lowercase :D
            if (HasCapitals(s[1])) SDB.donow("UPDATE players SET username = '" + s[1].ToLower() + "' WHERE username = '" + s[1] + "'");
            DateTime one = DateTime.Now.ToUniversalTime();
            PDB pdb = new PDB();
            DateTime two = DateTime.Now.ToUniversalTime();
            pdb.UID = Convert.ToInt64(s[0]);
            DateTime three = DateTime.Now.ToUniversalTime();
            pdb.username = s[1].Trim().ToLower();
            DateTime four = DateTime.Now.ToUniversalTime();
            pdb.password = s[3];
            DateTime five = DateTime.Now.ToUniversalTime();
            pdb.group = Byte.Parse(s[4]);
            DateTime six = DateTime.Now.ToUniversalTime();
            pdb.ip = s[10];
            DateTime seven = DateTime.Now.ToUniversalTime();
            pdb.color = s[11];
            DateTime eight = DateTime.Now.ToUniversalTime();
            try
            {
                pdb.warn = Convert.ToInt32(s[14]);
            }
            catch
            {
                pdb.warn = 0;
            }
            DateTime nine = DateTime.Now.ToUniversalTime();
            try
            {
                pdb.money = Convert.ToInt32(s[15]);
            }
            catch
            {
                pdb.money = 0;
            }
            DateTime ten = DateTime.Now.ToUniversalTime();
            foreach (string st in s[16].Split(','))
            {
                if (String.IsNullOrEmpty(st)) continue;
                pdb.Allowed.Add(st);
            }
            DateTime eleven = DateTime.Now.ToUniversalTime();
            foreach (string st in s[17].Split(','))
            {
                if (String.IsNullOrEmpty(st)) continue;
                pdb.Denied.Add(st);
            }
            DateTime twelve = DateTime.Now.ToUniversalTime();
            pdb.Title = s[18];
            DateTime thirteen = DateTime.Now.ToUniversalTime();
            foreach (string st in s[19].Split(','))
            {
                if (String.IsNullOrEmpty(st)) continue;
                pdb.Titles.Add(st);
            }
            DateTime fourteen = DateTime.Now.ToUniversalTime();
            PDB.DB.Add(pdb);
            DateTime fifteen = DateTime.Now.ToUniversalTime();
            int one1 = ((two - one).Milliseconds);
            int two1 = ((three - two).Milliseconds);
            int three1 = ((four - three).Milliseconds);
            int four1 = ((five - four).Milliseconds);
            int five1 = ((six - five).Milliseconds);
            int six1 = ((seven - six).Milliseconds);
            int seven1 = ((eight - seven).Milliseconds);
            int eight1 = ((nine - eight).Milliseconds);
            int nine1 = ((ten - nine).Milliseconds);
            int ten1 = ((eleven - ten).Milliseconds);
            int eleven1 = ((twelve - eleven).Milliseconds);
            int twelve1 = ((thirteen - twelve).Milliseconds);
            int thirteen1 = ((fourteen - thirteen).Milliseconds);
            int fourteen1 = ((fifteen - fourteen).Milliseconds);
            int fifteen1 = ((fifteen - one).Milliseconds);
            string sta = one1 + " " + two1 + " " + three1 + " " + four1 + " " + five1 + " " + six1 + " " + seven1 + " " + eight1 + " " + nine1 + " " + ten1 + " " + eleven1 + " " + twelve1 + " " + thirteen1 + " " + fourteen1 + " " + fifteen1;
            tolog.Add(sta);
            pcounti++;
        }
        catch (Exception e)
        {
            Console.WriteLine("Error:");
            Console.WriteLine(e.Message);
            Console.WriteLine(e.StackTrace);
            continue;
        }

                    // write to file
        StreamWriter sw = new StreamWriter(File.Create("test.txt"));
        foreach (string st in tolog)
        {
            sw.WriteLine(st);
        }
        sw.Flush();
        sw.Close();
    }
}

另外,请注意,写完大部分内容之后,我最后一次查看它,以确保我没有错过任何愚蠢的东西,并意识到我没有检查每个循环的前几行,我将它们添加到支票出来时也是这样。

另外,作为第二个注释,它在“之前”花了4分钟我添加了性能检查,现在不需要花费更多时间。

修改的 将Milliseconds更改为TotalMilliseconds会产生差异,但仅在将结果显示为double,而不是int时,会产生如下测试输出:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0.9765 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0.9765 0 0 0 0 0 0 0 0 0 0 0 0.9765
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0.9766 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

第一个数字最后没有添加到总数中。 另外,我应该提到的是,偶尔有一个混合在一起的0(也是第一次)但是我仍然像以前一样难倒,是时候剖析了。

编辑2 分析的结果,请注意,所有时间计数器和最后的进度条更新都不是永久性的,并且在最初的事件过程中不存在导致我首先尝试执行此操作的事件。 (即4-5分钟的加载时间)

Profile

4 个答案:

答案 0 :(得分:2)

您还没有真正告诉我们性能下降的位置,或者表明核心SQL查询需要多长时间,但有些想法:

  

List<string[]> p1 = SDB.get("Select * from players");

这是缓冲整个数据集;就个人而言,我将使用非缓冲API,即在到达时处理每一行。我也会使用输入的对象,而不是string[] - 像dapper-dot-net这样的东西可以非常巧妙地完成。

我还会分析这个单独的查询,看看它有多少时间与数据本地处理相比。

你似乎做了很多(2 * N + 1)的发现(PDB.find(s[1].Trim().ToLower())和UPDATE / DELETE等等;我认为你淹没了潜伏期。对于这个卷,我很想将源数据抛出(SqlBulkCopy)到数据库服务器上的一个表中并进行一些基于集合的查询(3;一次更新,一次删除,一次插入 - 或者MERGE如果可用) 在数据库

答案 1 :(得分:1)

有更好的方法来分析代码,比如使用合适的分析器,可以轻松获得免费代码和试用版!

如果你想以这种方式分析代码,我会看一下StopWatch类。

答案 2 :(得分:0)

  1. 您想使用TotalMilliseconds代替Milliseconds。代表5秒的TimeSpan对象,TotalMilliseconds为5000但Milliseconds为0!
  2. 您没有衡量该地区的时间#region Check if this user already has a PDB
  3. 您没有测量大写检查的时间:if (HasCapitals(s[1])) SDB.donow("UPDATE players SET username = '" + s[1].ToLower() + "' WHERE username = '" + s[1] + "'");

答案 3 :(得分:0)

我认为毫秒在这里不起作用,因为所有这些测量的操作都需要不到一毫秒。您可以尝试使用System.Diagnostics.Stopwatch并测量Ticks。此外,如果您尝试对每个步骤的相对性能进行基准测试,而不是测量每个玩家的数字,则累积它们(例如,总和为1,总和为1)并进行比较。

无论如何,我认为这不是一个分析代码的好方法,或者你可以通过对这样简单的分配时间进行基准测试来获得更多。您应该检查代码的其他部分,如SELECT语句或PDB.find