我试图弄清楚为什么我与 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/