2

В настоящее время я отлаживаю некоторые проблемы с производительностью для приложения, которое построено в .net-ядре, используя SQL Server в качестве базовой базы данных, а ядро ​​Entity Framework - как ОРМ.Разница в производительности базы данных: много небольших операций и некоторые более крупные операции

Я написал небольшую консоль-приложение для имитации некоторых рабочих нагрузок:

SqlConnection sqlConnection1;  

sqlConnection1 = new SqlConnection("Data Source=.\\SQLEXPRESS;Initial Catalog=Database;Integrated Security=True;MultipleActiveResultSets=true"); 

SqlCommand cmd = new SqlCommand(); 
SqlDataReader reader; 

Console.WriteLine("==== Table1 (1000000) key-lookup ===="); 

var sw1 = new Stopwatch(); 
sw1.Start(); 

for (int i = 0; i < 1000000; i++) 
{ 
    cmd.CommandText = "SELECT Value FROM table1 WHERE Id='" + i + "'"; 
    cmd.CommandType = CommandType.Text; 
    cmd.Connection = sqlConnection1; 

    sqlConnection1.Open(); 

    reader = cmd.ExecuteReader(); 

    var result = reader.Read(); 

    if (result) 
    { 
     var test = reader.GetString(0); 
    } 

    sqlConnection1.Close(); 
} 

sw1.Stop(); 

Console.WriteLine("Finished: " + sw1.Elapsed); 
Console.WriteLine("==== Table2 (1000) full-text-scan ===="); 

var sw2 = new Stopwatch(); 
sw2.Start(); 

for (int i = 0; i < 1000; i++) 
{ 
    cmd.CommandText = "SELECT Name FROM table2 WHERE Name LIKE '%" + i + "%'"; 
    cmd.CommandType = CommandType.Text; 
    cmd.Connection = sqlConnection1; 

    sqlConnection1.Open(); 

    reader = cmd.ExecuteReader(); 

    var result = reader.Read(); 

    if (result) 
    { 
     var test = reader.GetString(0); 
    } 

    sqlConnection1.Close(); 
} 

sw2.Stop(); 

Console.WriteLine("Finished: " + sw2.Elapsed); 
Console.ReadKey(); 

Для имитации Entity Framework, я открыл и закрыл соединение для каждого запроса.

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

Моя машина (приложение + SQL Server на той же системе):

  • Ключевые ищут: 1m53s
  • Полный текст: 4m31s

sERVER1 (приложение, дб через сеть):

  • Ключевые ищут: 30m49s (!!!!)
  • Полный текст: 9m19s

Сервер базы данных:

  • Ключевые ищут: 7m07s
  • Полный текст : 8m45s

Разница, похоже, связана с сетью, но все серверы просто виртуальная машина сидит на том же оборудовании. Кто-нибудь имеет идею, что может привести к этой плохой производительности сервера приложений?

+0

Я предлагаю параметризованные запросы, если вы пытаетесь имитировать EF. Это может немного улучшить производительность, но количество круглых поездок будет длинным полюсом в палатке. FWIW, вы должны иметь возможность получать более 2 тыс. Тривиальных запросов в секунду в сети 1 Гбит с однопоточным приложением на общем оборудовании. Это то, что вы видите локально на сервере db, поэтому VM не то, что может быть. –

+0

Итак, вы продемонстрировали, что сетевой трафик требует времени. Это не ново. Остальное, вероятно, можно отнести к протоколу named-pipe vs TCP/IP. –

ответ

0

мне не нравится эта строфа:

Для имитации Entity Framework, я открыл и закрыл соединение для каждого запроса.

Создание и закрытие соединений является довольно «дорогостоящим» процессом, поэтому существует шаблон проектирования программного обеспечения Connection pool. См. Статью Using Connection Pooling with SQL Server.

Также не рекомендуется иметь генератор нагрузки (в вашем случае - приложение командной строки) и экземпляр SQL-сервера на том же хосте, чтобы избежать взаимных помех и столкновения с использованием ресурсов операционной системы.

Я хотел бы предложить использовать третий сторонний инструмент т.е. Apache JMeter который обеспечивает JDBC Request sampler для проведения нагрузки, таким образом, вы получите более четкое представление о время отклика запросов и будешь иметь возможность сопоставить увеличение времени отклика с увеличением нагрузки. Когда вы дойдете до точки, в которой время отклика превысит допустимые пороговые значения (иначе говоря, «узкое место»), вы сможете увидеть основную причину и разрешить ее путем добавления дополнительных ресурсов или изменения конфигурации подключения к SQL-серверу или оптимизации запросов.

0

Много мелких операций явно хуже, чем несколько крупных операций. Любой запрос, который вы выполняете против SQL Server, будет иметь некоторые связанные с сетью накладные расходы.

Я не знаком с администрированием виртуальных машин, но независимо от того, они сидят на одном физическом сервере или нет, будут связаны служебные данные, связанные с TCP-IP-связью. Быстрые запросы будут страдать от значительных затрат на связь.

Интересным тестом было бы разделить ваши запросы партиями. Один быстрый способ (только оператор строительства):

const int batchSize = 100; 
for (int j = 0; j < batchSize; j ++) 
{ 
    string inStr = string.Join("AND ", $"Name LIKE '%{i+j}%'"); 
    cmd.CommandText = $"SELECT Name FROM table2 WHERE 1 = 1 {inStr}"; 
} 

Кроме того, важная вещь, чтобы знать, если вы используете пул соединений или нет. Если вы НЕ используете его, закрытие соединения действительно дорого в вашем сценарии (откройте соединение, запустите запрос, закройте его). Я заметил вашу строку подключения и, похоже, вы используете пул соединений (по умолчанию активен).