mysql - 为什么使用 mysql_real_connect 建立的与 MySQL 的单独连接似乎对插入设置了限制?

标签 mysql c multithreading

我试图弄清楚为什么我与 MySQL 数据库的连接似乎对每个连接每秒可以进行的 INSERT 数量有非常小的限制(小于 100)。我读过有关连接限制的内容,但这些都是关于每小时限制的。我遇到的是每秒限制。

我正在使用 MySQL C API 打开连接(每个线程一个)。在线程中,我只是以尽可能快的速度循环调用 mysql_query。我运行 10 秒,计算查询数量并在完成后报告这些查询。

使用 SELECT 语句进行查询,我得到以下结果:

  • 2 个线程:每个线程每秒 9800 次访问(9800*2 = 每秒 18K 总访问次数)
  • 5 个线程:每个线程每秒 8400 次访问(8400*5 = 42K 总访问次数)
  • 10 个线程:每个线程每秒 7300 次访问(7300*10 = 73K 总访问次数)

使用 INSERT 语句进行查询,我得到以下结果

  • 2 个线程:每个线程每秒 169 次访问(总共 338 次访问)
  • 5 个线程:每个线程每秒 168 次访问(总共 840 次访问)
  • 10 个线程:每个线程每秒 167 次访问(总共 1670 次访问)
  • 20 个线程:每个线程每秒 165 次访问(总共 3300 次访问)
  • 40 个线程:每个线程每秒 161 次访问(总共 6400 次访问)

似乎设置了某种限制。即使当我运行 40 个线程时,MySQL 数据库可以处理 6000 个插入,但连接每秒的插入次数不能超过 169 个。

如何增加连接可以进行的插入数量?

我正在使用一个简单的测试架构:

CREATE TABLE IF NOT EXISTS test.tbl ( tbl_idx INT NOT NULL AUTO_INCREMENT PRIMARY KEY, tbl_unique_id INT NOT NULL, type INT NOT NULL, date_time DATE NULL DEFAULT NULL, name LONGTEXT NULL DEFAULT NULL, description LONGTEXT NULL DEFAULT NULL, notes LONGTEXT NULL DEFAULT NULL );

我的 C 代码运行这些测试:

我的主要功能:

int running = 1;

int main(int argc, char* argv[])
{
  int secs = 10;
  int threadcnt = 20;
  int i;
  pthread_t readers[50], writers[50];

  mysql_library_init(0, NULL, NULL);

  for (i=0; i<threadcnt; i++)
  {
    pthread_create( &readers[i], NULL, dbtest_read, NULL);
    pthread_create( &writers[i], NULL, dbtest_write, NULL);
  }

  sleep(secs);
  running = 0;

  for (i=0; i<threadcnt; i++)
  {
    pthread_join(readers[i], NULL);
    pthread_join(writers[i], NULL);
  }

  mysql_library_end();

  return 0;

}

我的 SELECT 读者线程:

static void *dbtest_read(void *arg)
{
  char query_insert[1024] = "INSERT INTO tbl ( tbl_unique_id,  type,  date_time,  name,  notes) VALUES ('100', '33', NOW(), 'TestTarget', 'Alot of good notes here')";
  MYSQL mysql;
  MYSQL *conn;
  MYSQL_ROW row;
  MYSQL_RES *result;
  long cnt = 0;
  struct timespec start, stop;
  double elapsed = 0.0;

  printf("Starting Read Thread\n");
  mysql_init(&mysql);

  conn = mysql_real_connect(&mysql,"localhost", "sms", "ar.ch111", "test", 0, 0, 0);

  clock_gettime(CLOCK_MONOTONIC,&start);

  while (running)
  {
    mysql_query(conn, query_select);
    result = mysql_store_result(conn);
    row = mysql_fetch_row(result);
    cnt++;
    usleep(0);
  }
  clock_gettime(CLOCK_MONOTONIC,&stop);

  elapsed = (double) (stop.tv_sec - start.tv_sec) + (double) (stop.tv_nsec - start.tv_nsec)/1.0e9;

  printf("***DB Read Test*** selects: %ld  rate: %.2f /sec\n",cnt, ((float)(cnt)/elapsed));

  mysql_close(conn);

  pthread_exit(NULL);

  return 0;
}

我的 INSERT 作者线程:

static void *dbtest_write(void *arg)
{
char query_select[1024] = "SELECT tbl_unique_id, type, date_time, name FROM tbl WHERE tbl_idx = 1";
  MYSQL mysql;
  MYSQL *conn;
  long cnt = 0;
  struct timespec start, stop;
  double elapsed = 0.0;

  printf("Starting Write Thread\n");
  mysql_init(&mysql);

  conn = mysql_real_connect(&mysql,"localhost", "sms", "ar.ch111", "test", 0, 0, 0);

  clock_gettime(CLOCK_MONOTONIC,&start);

  while (running)
  {
    mysql_query(conn, query_insert);
    cnt++;
    usleep(0);
  }
  clock_gettime(CLOCK_MONOTONIC,&stop);

  elapsed = (double) (stop.tv_sec - start.tv_sec) + (double) (stop.tv_nsec - start.tv_nsec)/1.0e9;

  printf("***DB Write Test*** inserts: %ld  rate: %.2f /sec\n",cnt, ((float)(cnt)/elapsed));

  mysql_close(conn);

  pthread_exit(NULL);

  return 0;
}

最佳答案

所有症状都表明它与 I/O 延迟和带宽有关。由于在服务器执行查询时使用单个线程会阻塞,因此执行单个查询所需时间的近似方程为:

T = L + S / B

哪里

T represents time to execute a single query
L represents the I/O latency
S represents the size of the data
B represents the I/O bandwidth

因此,每秒的最大事务数为:

TPS = 1 / (L + S / B)

使用多个线程,并行执行多个查询所需的时间变为:

T = L + N * S / B

其中 N 代表线程数。

请注意,并行工作的多个线程所产生的延迟不会重复。不过,I/O 带宽会影响聚合数据传输。每秒的事务数变为:

TPS = N / (L + N * S / B)

随着线程数量的增加,延迟影响最终将变得可以忽略不计,最终会得到 TPS ~= S/B 这意味着您可以在 I/O 带宽允许的范围内尽可能快地运行。使用黑洞引擎,延迟变得可以忽略不计,这解释了您所看到的行为。

磁盘缓存等其他参数也会影响性能。总的来说,我认为这很好地解释了正在发生的事情。 MySQL 不允许在同一个数据库连接上执行多个查询,否则这将是一个很好的实验来证实我的理论。请注意,您没有将线程数增加到足以达到 I/O 带宽瓶颈的程度。

关于mysql - 为什么使用 mysql_real_connect 建立的与 MySQL 的单独连接似乎对插入设置了限制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30059877/

相关文章:

php - 用户注册/加入后创建用户目录(0777)

sql - MySQL - 条件选择

C 编程类型转换和 sizeof()

c++ - 在 OpenMP for 循环中调用函数

c++ - std::atomic 到底是什么?

java - 关闭后如何重新连接kafka生产者?

php - 如何在 Flex 中对 PHP 字符串使用换行符

c - 希望信号量超过 SEM_VALUE_MAX

c++ - 为什么TinyThread++这里不调用线程函数

mysql - 在触发器中使用局部变量