问题:为什么在并行执行时加入几乎空表的查询会导致MySQL性能下降?
下面是我正面临的问题的更详细解释。 MySQL中有两个表
CREATE TABLE first (
num int(10) NOT NULL,
UNIQUE KEY key_num (num)
) ENGINE=InnoDB
CREATE TABLE second (
num int(10) NOT NULL,
num2 int(10) NOT NULL,
UNIQUE KEY key_num (num, num2)
) ENGINE=InnoDB
第一个包含大约一千条记录。第二个是空的或包含很少的记录。它还包含双重索引,它在某种程度上与问题有关:单个索引的问题就消失了。现在我试图并行地对这些表进行大量相同的查询。每个查询都如下所示:
SELECT first.num
FROM first
LEFT JOIN second AS second_1 ON second_1.num = -1 # non-existent key
LEFT JOIN second AS second_2 ON second_2.num = -2 # non-existent key
LEFT JOIN second AS second_3 ON second_3.num = -3 # non-existent key
LEFT JOIN second AS second_4 ON second_4.num = -4 # non-existent key
LEFT JOIN second AS second_5 ON second_5.num = -5 # non-existent key
LEFT JOIN second AS second_6 ON second_6.num = -6 # non-existent key
WHERE second_1.num IS NULL
AND second_2.num IS NULL
AND second_3.num IS NULL
AND second_4.num IS NULL
AND second_5.num IS NULL
AND second_6.num IS NULL
我得到的问题是,在8核计算机上的性能几乎没有线性提升,我实际上有一个下降。即只有一个进程,我每秒的典型请求数大约是200.有两个进程而不是预期每秒增加300到400个查询我实际上有一个下降到150.对于10个进程我只有70个查询每秒。我用于测试的Perl代码如下所示:
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Parallel::Benchmark;
use SQL::Abstract;
use SQL::Abstract::Plugin::InsertMulti;
my $children_dbh;
foreach my $second_table_row_count (0, 1, 1000) {
print '#' x 80, "\nsecond_table_row_count = $second_table_row_count\n";
create_and_fill_tables(1000, $second_table_row_count);
foreach my $concurrency (1, 2, 3, 4, 6, 8, 10, 20) {
my $bm = Parallel::Benchmark->new(
'benchmark' => sub {
_run_sql();
return 1;
},
'concurrency' => $concurrency,
'time' => 3,
);
my $result = $bm->run();
}
}
sub create_and_fill_tables {
my ($first_table_row_count, $second_table_row_count) = @_;
my $dbh = dbi_connect();
{
$dbh->do(q{DROP TABLE IF EXISTS first});
$dbh->do(q{
CREATE TABLE first (
num int(10) NOT NULL,
UNIQUE KEY key_num (num)
) ENGINE=InnoDB
});
if ($first_table_row_count) {
my ($stmt, @bind) = SQL::Abstract->new()->insert_multi(
'first',
['num'],
[map {[$_]} 1 .. $first_table_row_count],
);
$dbh->do($stmt, undef, @bind);
}
}
{
$dbh->do(q{DROP TABLE IF EXISTS second});
$dbh->do(q{
CREATE TABLE second (
num int(10) NOT NULL,
num2 int(10) NOT NULL,
UNIQUE KEY key_num (num, num2)
) ENGINE=InnoDB
});
if ($second_table_row_count) {
my ($stmt, @bind) = SQL::Abstract->new()->insert_multi(
'second',
['num'],
[map {[$_]} 1 .. $second_table_row_count],
);
$dbh->do($stmt, undef, @bind);
}
}
}
sub _run_sql {
$children_dbh ||= dbi_connect();
$children_dbh->selectall_arrayref(q{
SELECT first.num
FROM first
LEFT JOIN second AS second_1 ON second_1.num = -1
LEFT JOIN second AS second_2 ON second_2.num = -2
LEFT JOIN second AS second_3 ON second_3.num = -3
LEFT JOIN second AS second_4 ON second_4.num = -4
LEFT JOIN second AS second_5 ON second_5.num = -5
LEFT JOIN second AS second_6 ON second_6.num = -6
WHERE second_1.num IS NULL
AND second_2.num IS NULL
AND second_3.num IS NULL
AND second_4.num IS NULL
AND second_5.num IS NULL
AND second_6.num IS NULL
});
}
sub dbi_connect {
return DBI->connect(
'dbi:mysql:'
. 'database=tmp'
. ';host=localhost'
. ';port=3306',
'root',
'',
);
}
对于这样的比较查询,在提高性能的同时执行:
SELECT first.num
FROM first
LEFT JOIN second AS second_1 ON second_1.num = 1 # existent key
LEFT JOIN second AS second_2 ON second_2.num = 2 # existent key
LEFT JOIN second AS second_3 ON second_3.num = 3 # existent key
LEFT JOIN second AS second_4 ON second_4.num = 4 # existent key
LEFT JOIN second AS second_5 ON second_5.num = 5 # existent key
LEFT JOIN second AS second_6 ON second_6.num = 6 # existent key
WHERE second_1.num IS NOT NULL
AND second_2.num IS NOT NULL
AND second_3.num IS NOT NULL
AND second_4.num IS NOT NULL
AND second_5.num IS NOT NULL
AND second_6.num IS NOT NULL
测试结果,cpu和磁盘使用量测量如下:
* table `first` have 1000 rows * table `second` have 6 rows: `[1,1],[2,2],..[6,6]` For query: SELECT first.num FROM first LEFT JOIN second AS second_1 ON second_1.num = -1 # non-existent key LEFT JOIN second AS second_2 ON second_2.num = -2 # non-existent key LEFT JOIN second AS second_3 ON second_3.num = -3 # non-existent key LEFT JOIN second AS second_4 ON second_4.num = -4 # non-existent key LEFT JOIN second AS second_5 ON second_5.num = -5 # non-existent key LEFT JOIN second AS second_6 ON second_6.num = -6 # non-existent key WHERE second_1.num IS NULL AND second_2.num IS NULL AND second_3.num IS NULL AND second_4.num IS NULL AND second_5.num IS NULL AND second_6.num IS NULL Results: concurrency: 1, speed: 162.910 / sec concurrency: 2, speed: 137.818 / sec concurrency: 3, speed: 130.728 / sec concurrency: 4, speed: 107.387 / sec concurrency: 6, speed: 90.513 / sec concurrency: 8, speed: 80.445 / sec concurrency: 10, speed: 80.381 / sec concurrency: 20, speed: 84.069 / sec System usage after for last 60 minutes of running query in 6 processes: $ iostat -cdkx 60 avg-cpu: %user %nice %system %iowait %steal %idle 74.82 0.00 0.08 0.00 0.08 25.02 Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util sda1 0.00 0.00 0.00 0.12 0.00 0.80 13.71 0.00 1.43 1.43 0.02 sdf10 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 sdf4 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 30.00 15.00 0.05 sdm 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf8 0.00 0.00 0.00 0.37 0.00 1.24 6.77 0.00 5.00 3.18 0.12 sdf6 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 sdf9 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 0.00 0.00 0.00 sdf 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf3 0.00 0.00 0.00 0.08 0.00 1.33 32.00 0.00 4.00 4.00 0.03 sdf2 0.00 0.00 0.00 0.17 0.00 1.37 16.50 0.00 3.00 3.00 0.05 sdf15 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf14 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf1 0.00 0.00 0.00 0.05 0.00 0.40 16.00 0.00 0.00 0.00 0.00 sdf13 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 sdf5 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 50.00 25.00 0.08 sdm2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdm1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf12 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 sdf11 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 sdf7 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 md0 0.00 0.00 0.00 0.97 0.00 13.95 28.86 0.00 0.00 0.00 0.00 ################################################################################ For query: SELECT first.num FROM first LEFT JOIN second AS second_1 ON second_1.num = 1 # existent key LEFT JOIN second AS second_2 ON second_2.num = 2 # existent key LEFT JOIN second AS second_3 ON second_3.num = 3 # existent key LEFT JOIN second AS second_4 ON second_4.num = 4 # existent key LEFT JOIN second AS second_5 ON second_5.num = 5 # existent key LEFT JOIN second AS second_6 ON second_6.num = 6 # existent key WHERE second_1.num IS NOT NULL AND second_2.num IS NOT NULL AND second_3.num IS NOT NULL AND second_4.num IS NOT NULL AND second_5.num IS NOT NULL AND second_6.num IS NOT NULL Results: concurrency: 1, speed: 875.973 / sec concurrency: 2, speed: 944.986 / sec concurrency: 3, speed: 1256.072 / sec concurrency: 4, speed: 1401.657 / sec concurrency: 6, speed: 1354.351 / sec concurrency: 8, speed: 1110.100 / sec concurrency: 10, speed: 1145.251 / sec concurrency: 20, speed: 1142.514 / sec System usage after for last 60 minutes of running query in 6 processes: $ iostat -cdkx 60 avg-cpu: %user %nice %system %iowait %steal %idle 74.40 0.00 0.53 0.00 0.06 25.01 Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util sda1 0.00 0.00 0.00 0.02 0.00 0.13 16.00 0.00 0.00 0.00 0.00 sdf10 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 sdf4 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 sdm 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf8 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 sdf6 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 0.00 0.00 0.00 sdf9 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 sdf 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf3 0.00 0.00 0.00 0.13 0.00 2.67 40.00 0.00 3.75 2.50 0.03 sdf2 0.00 0.00 0.00 0.23 0.00 2.72 23.29 0.00 2.14 1.43 0.03 sdf15 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf14 0.00 0.00 0.00 0.98 0.00 0.54 1.10 0.00 2.71 2.71 0.27 sdf1 0.00 0.00 0.00 0.08 0.00 1.47 35.20 0.00 8.00 6.00 0.05 sdf13 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf5 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 sdm2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdm1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf12 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 sdf11 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 0.00 0.00 0.00 sdf7 0.00 0.00 0.00 0.03 0.00 1.07 64.00 0.00 10.00 5.00 0.02 md0 0.00 0.00 0.00 1.70 0.00 15.92 18.74 0.00 0.00 0.00 0.00 ################################################################################ And this server has lots of free memory. Example of top: top - 19:02:59 up 4:23, 4 users, load average: 4.43, 3.03, 2.01 Tasks: 218 total, 1 running, 217 sleeping, 0 stopped, 0 zombie Cpu(s): 72.8%us, 0.7%sy, 0.0%ni, 26.3%id, 0.0%wa, 0.0%hi, 0.0%si, 0.1%st Mem: 71701416k total, 22183980k used, 49517436k free, 284k buffers Swap: 0k total, 0k used, 0k free, 1282768k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2506 mysql 20 0 51.7g 17g 5920 S 590 25.8 213:15.12 mysqld 9348 topadver 20 0 72256 11m 1428 S 2 0.0 0:01.45 perl 9349 topadver 20 0 72256 11m 1428 S 2 0.0 0:01.44 perl 9350 topadver 20 0 72256 11m 1428 S 2 0.0 0:01.45 perl 9351 topadver 20 0 72256 11m 1428 S 1 0.0 0:01.44 perl 9352 topadver 20 0 72256 11m 1428 S 1 0.0 0:01.44 perl 9353 topadver 20 0 72256 11m 1428 S 1 0.0 0:01.44 perl 9346 topadver 20 0 19340 1504 1064 R 0 0.0 0:01.89 top
有没有人知道为什么使用不存在的密钥进行查询会降低性能?
答案 0 :(得分:8)
写得很好的问题,显示了一些研究。
出于好奇,我尝试使用MySQL 5.6来查看有关这些查询的工具。
首先,请注意查询不同:
使用EXPLAIN提供了不同的计划:
EXPLAIN SELECT `first`.num
FROM `first`
LEFT JOIN `second` AS second_1 ON second_1.num = -1 # non-existent key
LEFT JOIN `second` AS second_2 ON second_2.num = -2 # non-existent key
LEFT JOIN `second` AS second_3 ON second_3.num = -3 # non-existent key
LEFT JOIN `second` AS second_4 ON second_4.num = -4 # non-existent key
LEFT JOIN `second` AS second_5 ON second_5.num = -5 # non-existent key
LEFT JOIN `second` AS second_6 ON second_6.num = -6 # non-existent key
WHERE second_1.num IS NULL
AND second_2.num IS NULL
AND second_3.num IS NULL
AND second_4.num IS NULL
AND second_5.num IS NULL
AND second_6.num IS NULL
;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE first index NULL key_num 4 NULL 1000 Using index
1 SIMPLE second_1 ref key_num key_num 4 const 1 Using where; Not exists; Using index
1 SIMPLE second_2 ref key_num key_num 4 const 1 Using where; Not exists; Using index
1 SIMPLE second_3 ref key_num key_num 4 const 1 Using where; Not exists; Using index
1 SIMPLE second_4 ref key_num key_num 4 const 1 Using where; Not exists; Using index
1 SIMPLE second_5 ref key_num key_num 4 const 1 Using where; Not exists; Using index
1 SIMPLE second_6 ref key_num key_num 4 const 1 Using where; Not exists; Using index
而不是
EXPLAIN SELECT `first`.num
FROM `first`
LEFT JOIN `second` AS second_1 ON second_1.num = 1 # existent key
LEFT JOIN `second` AS second_2 ON second_2.num = 2 # existent key
LEFT JOIN `second` AS second_3 ON second_3.num = 3 # existent key
LEFT JOIN `second` AS second_4 ON second_4.num = 4 # existent key
LEFT JOIN `second` AS second_5 ON second_5.num = 5 # existent key
LEFT JOIN `second` AS second_6 ON second_6.num = 6 # existent key
WHERE second_1.num IS NOT NULL
AND second_2.num IS NOT NULL
AND second_3.num IS NOT NULL
AND second_4.num IS NOT NULL
AND second_5.num IS NOT NULL
AND second_6.num IS NOT NULL
;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE second_1 ref key_num key_num 4 const 1 Using index
1 SIMPLE second_2 ref key_num key_num 4 const 1 Using index
1 SIMPLE second_3 ref key_num key_num 4 const 1 Using index
1 SIMPLE second_4 ref key_num key_num 4 const 1 Using index
1 SIMPLE second_5 ref key_num key_num 4 const 1 Using index
1 SIMPLE second_6 ref key_num key_num 4 const 1 Using index
1 SIMPLE first index NULL key_num 4 NULL 1000 Using index; Using join buffer (Block Nested Loop)
使用JSON格式,我们有:
EXPLAIN FORMAT=JSON SELECT `first`.num
FROM `first`
LEFT JOIN `second` AS second_1 ON second_1.num = -1 # non-existent key
LEFT JOIN `second` AS second_2 ON second_2.num = -2 # non-existent key
LEFT JOIN `second` AS second_3 ON second_3.num = -3 # non-existent key
LEFT JOIN `second` AS second_4 ON second_4.num = -4 # non-existent key
LEFT JOIN `second` AS second_5 ON second_5.num = -5 # non-existent key
LEFT JOIN `second` AS second_6 ON second_6.num = -6 # non-existent key
WHERE second_1.num IS NULL
AND second_2.num IS NULL
AND second_3.num IS NULL
AND second_4.num IS NULL
AND second_5.num IS NULL
AND second_6.num IS NULL
;
EXPLAIN
{
"query_block": {
"select_id": 1,
"nested_loop": [
{
"table": {
"table_name": "first",
"access_type": "index",
"key": "key_num",
"key_length": "4",
"rows": 1000,
"filtered": 100,
"using_index": true
}
},
{
"table": {
"table_name": "second_1",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"not_exists": true,
"using_index": true,
"attached_condition": "<if>(found_match(second_1), isnull(`test`.`second_1`.`num`), true)"
}
},
{
"table": {
"table_name": "second_2",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"not_exists": true,
"using_index": true,
"attached_condition": "<if>(found_match(second_2), isnull(`test`.`second_2`.`num`), true)"
}
},
{
"table": {
"table_name": "second_3",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"not_exists": true,
"using_index": true,
"attached_condition": "<if>(found_match(second_3), isnull(`test`.`second_3`.`num`), true)"
}
},
{
"table": {
"table_name": "second_4",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"not_exists": true,
"using_index": true,
"attached_condition": "<if>(found_match(second_4), isnull(`test`.`second_4`.`num`), true)"
}
},
{
"table": {
"table_name": "second_5",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"not_exists": true,
"using_index": true,
"attached_condition": "<if>(found_match(second_5), isnull(`test`.`second_5`.`num`), true)"
}
},
{
"table": {
"table_name": "second_6",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"not_exists": true,
"using_index": true,
"attached_condition": "<if>(found_match(second_6), isnull(`test`.`second_6`.`num`), true)"
}
}
]
}
}
而不是
EXPLAIN FORMAT=JSON SELECT `first`.num
FROM `first`
LEFT JOIN `second` AS second_1 ON second_1.num = 1 # existent key
LEFT JOIN `second` AS second_2 ON second_2.num = 2 # existent key
LEFT JOIN `second` AS second_3 ON second_3.num = 3 # existent key
LEFT JOIN `second` AS second_4 ON second_4.num = 4 # existent key
LEFT JOIN `second` AS second_5 ON second_5.num = 5 # existent key
LEFT JOIN `second` AS second_6 ON second_6.num = 6 # existent key
WHERE second_1.num IS NOT NULL
AND second_2.num IS NOT NULL
AND second_3.num IS NOT NULL
AND second_4.num IS NOT NULL
AND second_5.num IS NOT NULL
AND second_6.num IS NOT NULL
;
EXPLAIN
{
"query_block": {
"select_id": 1,
"nested_loop": [
{
"table": {
"table_name": "second_1",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"using_index": true
}
},
{
"table": {
"table_name": "second_2",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"using_index": true
}
},
{
"table": {
"table_name": "second_3",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"using_index": true
}
},
{
"table": {
"table_name": "second_4",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"using_index": true
}
},
{
"table": {
"table_name": "second_5",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"using_index": true
}
},
{
"table": {
"table_name": "second_6",
"access_type": "ref",
"possible_keys": [
"key_num"
],
"key": "key_num",
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"using_index": true
}
},
{
"table": {
"table_name": "first",
"access_type": "index",
"key": "key_num",
"key_length": "4",
"rows": 1000,
"filtered": 100,
"using_index": true,
"using_join_buffer": "Block Nested Loop"
}
}
]
}
}
查看运行时由性能模式检测的表,我们有:
truncate table performance_schema.objects_summary_global_by_type;
select * from performance_schema.objects_summary_global_by_type
where OBJECT_NAME in ("first", "second");
OBJECT_TYPE OBJECT_SCHEMA OBJECT_NAME COUNT_STAR SUM_TIMER_WAIT MIN_TIMER_WAIT AVG_TIMER_WAIT MAX_TIMER_WAIT
TABLE test first 0 0 0 0 0
TABLE test second 0 0 0 0 0
SELECT `first`.num
FROM `first`
LEFT JOIN `second` AS second_1 ON second_1.num = -1 # non-existent key
LEFT JOIN `second` AS second_2 ON second_2.num = -2 # non-existent key
LEFT JOIN `second` AS second_3 ON second_3.num = -3 # non-existent key
LEFT JOIN `second` AS second_4 ON second_4.num = -4 # non-existent key
LEFT JOIN `second` AS second_5 ON second_5.num = -5 # non-existent key
LEFT JOIN `second` AS second_6 ON second_6.num = -6 # non-existent key
WHERE second_1.num IS NULL
AND second_2.num IS NULL
AND second_3.num IS NULL
AND second_4.num IS NULL
AND second_5.num IS NULL
AND second_6.num IS NULL
;
(...)
select * from performance_schema.objects_summary_global_by_type
where OBJECT_NAME in ("first", "second");
OBJECT_TYPE OBJECT_SCHEMA OBJECT_NAME COUNT_STAR SUM_TIMER_WAIT MIN_TIMER_WAIT AVG_TIMER_WAIT MAX_TIMER_WAIT
TABLE test first 1003 5705014442 1026171 5687889 87356557
TABLE test second 6012 271786533972 537266 45207298 1123939292
而不是:
select * from performance_schema.objects_summary_global_by_type
where OBJECT_NAME in ("first", "second");
OBJECT_TYPE OBJECT_SCHEMA OBJECT_NAME COUNT_STAR SUM_TIMER_WAIT MIN_TIMER_WAIT AVG_TIMER_WAIT MAX_TIMER_WAIT
TABLE test first 1003 5211074603 969338 5195454 61066176
TABLE test second 24 458656783 510085 19110361 66229860
缩放的查询几乎没有表second
中的表IO。
不缩放的查询在表second
中执行6K表IO,或者是表first
的6倍表。
这是因为查询计划不同,因为查询不同(IS NOT NULL与IS NULL)。
我认为这回答了与绩效相关的问题。
请注意,我的测试中两个查询都返回了1000行,这可能不是您想要的。 在调整查询以使其更快之前,请确保它按预期工作。
答案 1 :(得分:1)
我建议尝试一种方法,其中每个fork
都使用自己的连接(它看起来我现在$children_dbh
,它拥有数据库连接,是一个共享变量)。或者,更好的是,实施所谓的connection pool
,每个客户端流程在需要时都会从中获取连接,并且会将其重新提供回来。何时不再需要它。
检查this answer以获取更多详细信息:给出它的线程是关于Java的,但它实际上是关于MySQL组织的一些通用原则。 this answer也可能有用。
P.S。有些类似的情况(我认为)被描述为here,并且有关于如何组织连接池的详细说明。