<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">今天接到一个需求,说在一个mysql库上面做20个并发的纯查询,需要40s左右,但是单条的语句执行时间大概在1s左右,而且并发加得愈多,需要耗费的时间越长。</span>
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: <derived2> 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,<span style="font-family: Arial, Helvetica, sans-serif;">certificate_code</span><span style="font-family: Arial, Helvetica, sans-serif;">) --这个索引是我后面添加的。</span>
索引的选择率:
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: <derived2> 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的性能!