今天接到一个需求,说在一个mysql库上面做20个并发的纯查询,需要40s左右,但是单条的语句执行时间大概在1s左右,而且并发加得愈多,需要耗费的时间越长。
mysql> explain select a.*
-> from (select fci.certificate_id certificateID,
-> fci.certificate_code certificateCode,
-> fci.paper_document_code paperDocumentCode,
-> fci.archive_by createByUM,
-> fci.status status,
-> fci.file_type archiveType
-> from fs_certificate_info fci
-> where 1 = 1
-> and fci.ledger_id = '1'
-> and exists
-> (select fpi.period_name
-> from fs_period_info fpi
-> where fpi.period_year = '2015'
-> and fpi.period_month between '02' + 0 and '02' + 0
-> and source = '1'
-> and fpi.period_name = fci.period_name)
-> and fci.file_type ='010200'
-> and exists
-> (select fcli.certificate_id
-> from fs_certificate_line_info fcli
-> where 1 = 1
-> and fcli.company_segment_code in ('000000')
-> and fcli.business_segment_code in ('0101')
-> and fcli.is_delete = '0'
-> and fcli.certificate_id = fci.certificate_id)
-> order by certificate_code) a limit 0,
-> 20
-> \G;
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table:
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 48711
Extra: NULL
*************************** 2. row ***************************
id: 2
select_type: DERIVED
table: fci
type: ref
possible_keys: idx_leger_id,xl_test
key: xl_test
key_len: 66
ref: const,const
rows: 48711
Extra: Using where
*************************** 3. row ***************************
id: 4
select_type: DEPENDENT SUBQUERY
table: fcli
type: ref
possible_keys: idx_certificate_id,idx_segment
key: idx_certificate_id
key_len: 8
ref: d0fams.fci.certificate_id
rows: 1
Extra: Using index condition; Using where
*************************** 4. row ***************************
id: 3
select_type: DEPENDENT SUBQUERY
table: fpi
type: ref
possible_keys: indexYearAndMonth,idx_period_name
key: idx_period_name
key_len: 33
ref: d0fams.fci.period_name
rows: 1
Extra: Using where
4 rows in set (0.00 sec)
PRIMARY KEY (`certificate_info_id`),
UNIQUE KEY `certificate_info_id_unique` (`certificate_info_id`),
UNIQUE KEY `certificate_id_unique` (`certificate_id`),
KEY `idx_accrediation` (`accreditation`,`accreditation_replaceable`),
KEY `idx_certificate_code` (`certificate_code`),
KEY `idx_period_name` (`period_name`),
KEY `idx_leger_id` (ledger_id,file_type,certificate_code)
KEY `xl_test` (ledger_id,file_type,certificate_code) --这个索引是我后面添加的。
索引的选择率:
mysql> select count(1),ledger_id from fs_certificate_info group by ledger_id;
+----------+-----------+
| count(1) | ledger_id |
+----------+-----------+
| 108240 | 1 |
| 1000 | 86 |
| 10030 | 99 |
+----------+-----------+
3 rows in set (0.17 sec)
mysql> select count(1),file_type from fs_certificate_info group by file_type;
+----------+-----------+
| count(1) | file_type |
+----------+-----------+
| 13170 | 010100 |
| 106100 | 010200 |
+----------+-----------+
2 rows in set (0.12 sec)
http://blog.itpub.net/7607759/viewspace-719645/
确实说的很有道理,通过二级索引找到乱序的聚簇索引的key值,然后在找需要的列。我也觉得这是原因,所以试了一下通过all的方式访问表,但是结果还是和原来的一样,单条很快,并发20 需要50s左右!
mysql> alter table fs_certificate_info add index xl_test(ledger_id,file_type,certificate_code);explain select a.* from (select fci.certificate_id certper_document_code paperDocumentCode, fci.archive_by createByUM, fci.status status, fci.file_type archiveType from fs_certificate_info fci ignore index(idx_leger_id,xl_test) where 1 = 1 and fci.ledger_id = '1' and exists (select 1 from fs_period_info fpi where fpi.period_year = '2015' and fpi.period_month between '02' + 0 and '02' + 0 and source = '1' and fpi.period_name = fci.period_name) and fc and fcli.company_segment_code in ('000000') and fcli.business_segment_code in ('0101') and fcli.is_delete = '0' and fcli.certificate_id = fci.certificate_id) order by certificate_code) a limit 0,20\G;
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table:
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 97422
Extra: NULL
*************************** 2. row ***************************
id: 2
select_type: DERIVED
table: fci
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 97422
Extra: Using where; Using filesort
*************************** 3. row ***************************
id: 4
select_type: DEPENDENT SUBQUERY
table: fcli
type: ref
possible_keys: idx_certificate_id,idx_segment
key: idx_certificate_id
key_len: 8
ref: d0fams.fci.certificate_id
rows: 1
Extra: Using index condition; Using where
*************************** 4. row ***************************
id: 3
select_type: DEPENDENT SUBQUERY
table: fpi
type: ref
possible_keys: indexYearAndMonth,idx_period_name
key: idx_period_name
key_len: 33
ref: d0fams.fci.period_name
rows: 1
Extra: Using where
4 rows in set (0.00 sec)
executemysql.sh
#!/bin/sh
echo `date`
qry='select a.*
from (select fci.certificate_id certificateID,
fci.certificate_code certificateCode,
fci.paper_document_code paperDocumentCode,
fci.archive_by createByUM,
fci.status status,
fci.file_type archiveType
from fs_certificate_info fci ignore index(idx_leger_id,xl_test)
where 1 = 1
and fci.ledger_id = '1'
and exists
(select 1
from fs_period_info fpi
where fpi.period_year = '2015'
and fpi.period_month between '02' + 0 and '02' + 0
and source = '1'
and fpi.period_name = fci.period_name)
and fci.file_type ='010200'
and exists
(select 1
from fs_certificate_line_info fcli
where 1 = 1
and fcli.company_segment_code in ('000000')
and fcli.business_segment_code in ('0101')
and fcli.is_delete = '0'
and fcli.certificate_id = fci.certificate_id)
order by certificate_code) a limit 0,20;'
mysql -uroot -pxxxxxx --socket=/paic/my5003/var/mysql.sock --port=5003 << eof
use d0fams
$qry
exit
eof
echo `date`
cnsz081161:d0fams :MAS > more 1.sh
echo `date`
sh executemysql.sh &
sh executemysql.sh &
sh executemysql.sh &
sh executemysql.sh &
sh executemysql.sh &
sh executemysql.sh &
sh executemysql.sh &
sh executemysql.sh &
sh executemysql.sh &
sh executemysql.sh &
sh executemysql.sh &
sh executemysql.sh &
echo `date`
现在没有办法了,不知道原因了!哎,只能从sql入手了,使用了exsits的方式,是否可以改写为join的方式。抱着试试的心态改了一下。
mysql> explain select fci.certificate_id certificateID,
-> fci.certificate_code certificateCode,
-> fci.paper_document_code paperDocumentCode,
-> fci.archive_by createByUM,
-> fci.status status,
-> fci.file_type archiveType
-> from fs_certificate_info fci inner join fs_period_info fpi on fpi.period_name = fci.period_name
-> inner join fs_certificate_line_info fcli on fcli.certificate_id = fci.certificate_id
-> where fci.ledger_id = '1' and fci.file_type ='010200' and fpi.period_year = '2015'
-> and fpi.period_month between '02' + 0 and '02' + 0
-> and source = '1'
-> and fcli.company_segment_code in ('000000')
-> and fcli.business_segment_code in ('0101')
-> and fcli.is_delete = '0'
-> order by certificate_code limit 0,20\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: fci
type: ref
possible_keys: certificate_id_unique,idx_period_name,idx_leger_id,xl_test
key: xl_test
key_len: 66
ref: const,const
rows: 48711
Extra: Using where
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: fpi
type: ref
possible_keys: indexYearAndMonth,idx_period_name
key: idx_period_name
key_len: 33
ref: d0fams.fci.period_name
rows: 1
Extra: Using where
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: fcli
type: ref
possible_keys: idx_certificate_id,idx_segment
key: idx_certificate_id
key_len: 8
ref: d0fams.fci.certificate_id
rows: 1
Extra: Using index condition; Using where
3 rows in set (0.00 sec)
mysql> select fci.certificate_id certificateID,
-> fci.certificate_code certificateCode,
-> fci.paper_document_code paperDocumentCode,
-> fci.archive_by createByUM,
-> fci.status status,
-> fci.file_type archiveType
-> from fs_certificate_info fci inner join fs_period_info fpi on fpi.period_name = fci.period_name
-> inner join fs_certificate_line_info fcli on fcli.certificate_id = fci.certificate_id
-> where fci.ledger_id = '1' and fci.file_type ='010200' and fpi.period_year = '2015'
-> and fpi.period_month between '02' + 0 and '02' + 0
-> and source = '1'
-> and fcli.company_segment_code in ('000000')
-> and fcli.business_segment_code in ('0101')
-> and fcli.is_delete = '0'
-> order by certificate_code limit 0,20;
+---------------+-------------------+-------------------+------------+--------+-------------+
| certificateID | certificateCode | paperDocumentCode | createByUM | status | archiveType |
+---------------+-------------------+-------------------+------------+--------+-------------+
| 12 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 12 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 12 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 13 | cerfiticatecode01 | NULL | CAOJING260 | 100 | 010200 |
| 13 | cerfiticatecode01 | NULL | CAOJING260 | 100 | 010200 |
| 13 | cerfiticatecode01 | NULL | CAOJING260 | 100 | 010200 |
| 15 | cerfiticatecode01 | NULL | CAOJING260 | 50 | 010200 |
| 15 | cerfiticatecode01 | NULL | CAOJING260 | 50 | 010200 |
| 15 | cerfiticatecode01 | NULL | CAOJING260 | 50 | 010200 |
| 17 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 17 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 17 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 19 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 19 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 19 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 111 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 111 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 111 | cerfiticatecode01 | NULL | CAOJING260 | 10 | 010200 |
| 112 | cerfiticatecode01 | NULL | CAOJING260 | 90 | 010200 |
| 112 | cerfiticatecode01 | NULL | CAOJING260 | 90 | 010200 |
+---------------+-------------------+-------------------+------------+--------+-------------+
20 rows in set (0.03 sec)
总结:mysql没有oracle那么强大的cbo,所以需要有严格的规范和高手写高效的sql,才能发挥mysql的性能!