数据库性能差异:许多小型操作与一些较大的操作

时间:2017-02-05 11:28:41

标签: sql-server performance entity-framework performance-testing database-performance

我正在调试使用SQL Server作为底层数据库构建的.net核心应用程序的一些性能问题,以及作为ORM的Entity Framework Core。

我编写了一个小型控制台应用程序来模拟一些工作负载:

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();

模拟实体框架我已经打开并关闭了每个查询的连接。

安装在server1上的应用程序,数据库位于数据库服务器上,当我运行此应用程序时,我得到以下结果:

我的机器(app +同一系统上的SQL Server):

  • 寻找钥匙:1m53s
  • 全文:4m31s

Server1(app,db via network):

  • 寻找钥匙:30m49s(!!!!)
  • 全文:9m19s

数据库服务器:

  • 寻找钥匙:7m07s
  • 全文:8m45s

差异似乎与网络相关,但服务器都只是VM坐在同一硬件上。有没有人有一个想法,什么可能导致应用服务器的这种糟糕的性能?

2 个答案:

答案 0 :(得分:0)

很多小型企业显然比一些大型企业更糟糕。您针对SQL Server运行的任何查询都会产生一些与网络相关的开销。

我不熟悉VM管理,但无论它们是否位于同一物理服务器上,都会产生与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}";
}

此外,了解您是否使用连接池也很重要。如果你不使用它,关闭连接在你的场景中非常昂贵(打开连接,运行查询,关闭它)。我注意到你的连接字符串,它看起来你正在使用连接池(活动的默认值)。

答案 1 :(得分:0)

我不喜欢这个节:

  

模拟实体框架我已经打开并关闭了每个查询的连接。

创建和关闭连接是一个非常“昂贵”的过程,因此有一个Connection pool软件设计模式。有关详细信息,请参阅Using Connection Pooling with SQL Server文章。

此外,不建议在同一主机上安装负载生成器(在您的情况下 - 命令行应用程序)和SQL Server实例,以避免使用操作系统资源时的相互干扰和冲突。

我建议使用第三方工具即Apache JMeter,它提供JDBC Request sampler来执行加载,这样您就可以更清晰地查看查询响应时间并且可以关联增加随着负载的增加,响应时间。当您达到响应时间超过可接受阈值(即“瓶颈”)的程度时,您将能够看到根本原因并通过添加更多资源或修改SQL Server连接配置或优化查询来解决它。