【问题标题】:Database performance difference in performance: a lot of small operations vs some larger operations数据库性能差异:很多小操作与一些大操作
【发布时间】:2017-02-05 11:28:41
【问题描述】:

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

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

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):

  • key-seek:1m53s
  • 全文:4 分 31 秒

Server1 (app, db via network):

  • 键位:30 分 49 秒 (!!!!)
  • 全文:9 分 19 秒

数据库服务器:

  • 键搜索:7m07s
  • 全文:8 分 45 秒

差异似乎与网络有关,但服务器都只是位于同一硬件上的虚拟机。有谁知道,是什么导致应用服务器性能不佳?

【问题讨论】:

  • 如果您尝试模拟 EF,我建议使用参数化查询。这可能会稍微提高性能,但往返次数将是帐篷中的长杆。 FWIW,您应该能够在通用硬件上使用单线程应用程序在 1gb 网络上实现每秒超过 2K 的琐碎查询。这就是您在数据库服务器上本地看到的内容,因此虚拟机不是它可能的样子。
  • 所以你证明了网络流量需要时间。这并不新鲜。其余的可能归因于命名管道协议与 TCP/IP。

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


【解决方案1】:

我不喜欢这节:

为了模拟实体框架,我为每个查询打开和关闭了连接。

创建和关闭连接是一个相当“昂贵”的过程,因此有一个Connection pool 软件设计模式。详情见Using Connection Pooling with SQL Server文章。

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

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

【讨论】:

    【解决方案2】:

    很多小操作显然比一些大操作更糟糕。对 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}";
    }
    

    另外,重要的是要知道您是否使用连接池。如果你不使用它,在你的场景中关闭连接真的很昂贵(打开连接,运行查询,关闭它)。我注意到你的连接字符串,看起来你正在使用连接池(由默认)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-05
      • 2010-10-02
      • 1970-01-01
      • 2018-01-06
      相关资源
      最近更新 更多