C # медленная загрузка из базы данных и экстраполяция в объекты - PullRequest
2 голосов
/ 02 мая 2011

Хорошо, я работаю над тем, чтобы ускорить загрузку моего сервера. В основном это предварительная загрузка учетных записей пользователей из базы данных и добавление их в список объектов игрока с 13 переменными в каждой.

Я решил, что первым шагом было выяснить, какие части системы занимают больше всего времени, поэтому я настроил переменные DateTime для подсчета количества миллисекунд, которые каждый фрагмент кода выполнял.

У нас есть около 40 тыс. Учетных записей в базе данных, и все они почти мгновенно загружаются в список строк, которые мы затем экстраполируем в их переменные. Это не самый эффективный способ сделать что-то, но он приличный с точки зрения скорости , и это работает и без ошибок.

в любом случае, требуется около 4 минут для экстраполяции учетных записей 40k в их последующие объекты, установки переменных и добавления объекта в список предварительно загруженных данных.

Я добавил переменные DateTime вокруг каждого параметра переменной, а затем установил время выполнения, была только одна проблема, все числа были 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 0

Я тестирую первоначальное создание объекта, 13 переменных, добавление объекта в список, затем вывожу общее время. Это не должно быть точным, просто чтобы помочь мне понять, где мне нужно что-то изменить, я был немного расстроен из-за 40 тыс. Строк 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 минуты, прежде чем я добавил проверку производительности, теперь это не займет много времени.

EDIT изменение миллисекунд на TotalMilliseconds дает различие, но только в том, что результаты отображаются в виде двойных, а не целых чисел, что приводит к выводу теста, подобному следующему:

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

Первый номер не добавляется в итог в конце. Кроме того, я должен упомянуть, что время от времени есть 1, смешанный с 0 (это было и в первый раз), но я все еще в замешательстве, как и раньше, время для профиля.

РЕДАКТИРОВАТЬ 2 Результаты профилирования, обратите внимание, что все счетчики времени и обновление индикатора выполнения в конце не являются постоянными, и их не было в первоначальном ходе событий, которые привели меня к попытке сделать это в первую очередь. (т.е. время загрузки 4-5 минут)

Profile

Ответы [ 4 ]

2 голосов
/ 02 мая 2011

Вы на самом деле не дали нам никакой информации о том, где происходит снижение производительности ... или указали, сколько времени занимает основной запрос 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 голос
/ 02 мая 2011

Есть гораздо лучшие способы профилировать код, например, с помощью правильного профилировщика, есть бесплатные и пробные версии, доступные легко!

Если вы хотите профилировать код таким способом, я бы посмотрелв классе StopWatch.

0 голосов
/ 02 мая 2011

Я думаю, что миллисекунды здесь не сработают, поскольку все эти измеренные операции занимают намного меньше миллисекунды.Вы можете попробовать System.Diagnostics.Stopwatch и измерить тики.Кроме того, если вы пытаетесь измерить относительную производительность каждого шага, вместо того, чтобы измерять эти числа для каждого игрока, накапливайте их (например, сумма одного1, сумма одного2) и сравнивайте.Это хороший способ для профилирования кода, или вы получите много пользы, если будете сравнивать такие простые времена назначения.Вы должны проверить другие части вашего кода, такие как оператор SELECT или PDB.find

0 голосов
/ 02 мая 2011
  1. Вы хотите использовать TotalMilliseconds вместо Milliseconds.TimeSpan объект, который представляет 5 секунд, имеет 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] + "'");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...