正在浏览 MySQL 里的文章

我一直是使用mysql这个数据库软件,它工作比较稳定,效率也很高。在遇到严重性能问题时,一般都有这么几种可能:

1、索引没有建好;
2、sql写法过于复杂;
3、配置错误;
4、机器实在负荷不了;

1、索引没有建好

如果看到mysql消耗的cpu很大,可以用mysql的client工具来检查。

在linux下执行

/usr/local/mysql/bin/mysql -hlocalhost -uroot -p

输入密码,如果没有密码,则不用-p参数就可以进到客户端界面中。

看看当前的运行情况

show full processlist

可以多运行几次

这个命令可以看到当前正在执行的sql语句,它会告知执行的sql、数据库名、执行的状态、来自的客户端ip、所使用的帐号、运行时间等信息

在我的cache后端,这里面大部分时间是看不到显示任何sql语句的,我认为这样才算比较正常。如果看到有很多sql语句,那么这台mysql就一定会有性能问题

如果出现了性能问题,则可以进行分析:

1、是不是有sql语句卡住了?

这是出现比较多的情况,如果数据库是采用myisam,那么有可能有一个写入的线程会把数据表给锁定了,如果这条语句不结束,则其它语句也无法运行。

查看processlist里的time这一项,看看有没有执行时间很长的语句,要留意这些语句。

2、大量相同的sql语句正在执行

如果出现这种情况,则有可能是该sql语句执行的效率低下,同样要留意这些语句。

然后把你所怀疑的语句统统集合一下,用desc(explain)来检查这些语句。

首先看看一个正常的desc输出:

mysql> desc select * from imgs where imgid=1651768337;
+—-+————-+——-+——-+—————+———+———+——-+——+——-+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+—-+————-+——-+——-+—————+———+———+——-+——+——-+
|  1 | SIMPLE      | imgs  | const | PRIMARY       | PRIMARY | 8       | const |    1 |       |
+—-+————-+——-+——-+—————+———+———+——-+——+——-+
1 row in set (0.00 sec)

注意key、rows和Extra这三项,这条语句返回的结果说明了该sql会使用PRIMARY主键索引来查询,结果集数量为1条,Extra没有显 示,证明没有用到排序或其他操作。由此结果可以推断,mysql会从索引中查询imgid=1651768337这条记录,然后再到真实表中取出所有字 段,是很简单的操作。

key是指明当前sql会使用的索引,mysql执行一条简单语句时只能使用到一条索引,注意这个限制;rows是返回的结果集大小,结果集就是使用该索引进行一次搜索的所有匹配结果;Extra一般会显示查询和排序的方式,。

如果没有使用到key,或者rows很大而用到了filesort排序,一般都会影响到效率,例如:

mysql> desc select * from imgs where userid=”7mini” order by clicks desc limit 10;
+—-+————-+——-+——+—————+——+———+——+——-+—————————–+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra                       |
+—-+————-+——-+——+—————+——+———+——+——-+—————————–+
|  1 | SIMPLE      | imgs  | ALL  | NULL          | NULL | NULL    | NULL | 12506 | Using where; Using filesort |
+—-+————-+——-+——+—————+——+———+——+——-+—————————–+
1 row in set (0.00 sec)

这条sql结果集会有12506条,用到了filesort,所以执行起来会非常消耗效率的。这时mysql执行时会把整个表扫描一遍,一条一条去找到匹 配userid=”7mini”的记录,然后还要对这些记录的clicks进行一次排序,效率可想而知。真实执行时如果发现还比较快的话,那是因为服务器 内存还足够将12506条比较短小的记录全部读入内存,所以还比较快,但是并发多起来或者表大起来的话,效率问题就严重了。

这时我把userid加入索引:

create index userid on imgs (userid);

然后再检查:

mysql> desc select * from imgs where userid=”7mini” order by clicks desc limit 10;
+—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
| id | select_type | table | type | possible_keys | key    | key_len | ref   | rows | Extra                       |
+—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
|  1 | SIMPLE      | imgs  | ref  | userid        | userid | 51      | const |    8 | Using where; Using filesort |
+—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
1 row in set (0.00 sec)

嗯,这时可以看到mysql使用了userid这个索引搜索了,用userid索引一次搜索后,结果集有8条。然后虽然使用了filesort一条一条排序,但是因为结果集只有区区8条,效率问题得以缓解。

但是,如果我用别的userid查询,结果又会有所不同:

mysql> desc select * from imgs where userid=”admin” order by clicks desc limit 10;
+—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
| id | select_type | table | type | possible_keys | key    | key_len | ref   | rows | Extra                       |
+—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
|  1 | SIMPLE      | imgs  | ref  | userid        | userid | 51      | const | 2944 | Using where; Using filesort |
+—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
1 row in set (0.00 sec)

这个结果和userid=”7mini”的结果基本相同,但是mysql用userid索引一次搜索后结果集的大小达到2944条,这2944条记录都会 加入内存进行filesort,效率比起7mini那次来说就差很多了。这时可以有两种办法可以解决,第一种办法是再加一个索引和判断条件,因为我只需要 根据点击量取最大的10条数据,所以有很多数据我根本不需要加进来排序,比如点击量小于10的,这些数据可能占了很大部分。

我对clicks加一个索引,然后加入一个where条件再查询:

create index clicks on imgs(clicks);

mysql> desc select * from imgs where userid=”admin” order by clicks desc limit 10;
+—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
| id | select_type | table | type | possible_keys | key    | key_len | ref   | rows | Extra                       |
+—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
|  1 | SIMPLE      | imgs  | ref  | userid,clicks | userid | 51      | const | 2944 | Using where; Using filesort |
+—-+————-+——-+——+—————+——–+———+——-+——+—————————–+
1 row in set (0.00 sec)

这时可以看到possible_keys变成了userid,clicks,possible_keys是可以匹配的所有索引,mysql会从 possible_keys中自己判断并取用其中一个索引来执行语句,值得注意的是,mysql取用的这个索引未必是最优化的。这次查询mysql还是使 用userid这个索引来查询的,并没有按照我的意愿,所以结果还是没有什么变化。改一下sql加上use index强制mysql使用clicks索引:

mysql> desc select * from imgs use index (clicks) where userid=’admin’ and clicks>10 order by clicks desc limit 10
+—-+————-+——-+——-+—————+——–+———+——+——+————-+
| id | select_type | table | type  | possible_keys | key    | key_len | ref  | rows | Extra       |
+—-+————-+——-+——-+—————+——–+———+——+——+————-+
|  1 | SIMPLE      | imgs  | range | clicks        | clicks | 4       | NULL | 5455 | Using where |
+—-+————-+——-+——-+—————+——–+———+——+——+————-+
1 row in set (0.00 sec)

这时mysql用到了clicks索引进行查询,但是结果集比userid还要大!看来还要再进行限制:

mysql> desc select * from imgs use index (clicks) where userid=’admin’ and clicks>1000 order by clicks desc limit 10
+—-+————-+——-+——-+—————+——–+———+——+——+————-+
| id | select_type | table | type  | possible_keys | key    | key_len | ref  | rows | Extra       |
+—-+————-+——-+——-+—————+——–+———+——+——+————-+
|  1 | SIMPLE      | imgs  | range | clicks        | clicks | 4       | NULL |  312 | Using where |
+—-+————-+——-+——-+—————+——–+———+——+——+————-+
1 row in set (0.00 sec)

加到1000的时候结果集变成了312条,排序效率应该是可以接受。

不过,采用换索引这种优化方式需要取一个采样点,比如这个例子中的1000这个数字,这样,对userid的每个数值,都要去找一个采样点,这样对程序来 说是很难办的。如果按1000取样的话,那么userid=’7mini’这个例子中,取到的结果将不会是8条,而是2条,给用户造成了困惑。

当然还有另一种办法,加入双索引:

create index userid_clicks on imgs (userid, clicks)

mysql> desc select * from imgs where userid=”admin” order by clicks desc limit 10;
+—-+————-+——-+——+———————-+—————+———+——-+——+————-+
| id | select_type | table | type | possible_keys        | key           | key_len | ref   | rows | Extra       |
+—-+————-+——-+——+———————-+—————+———+——-+——+————-+
|  1 | SIMPLE      | imgs  | ref  | userid,userid_clicks | userid_clicks | 51      | const | 2944 | Using where |
+—-+————-+——-+——+———————-+—————+———+——-+——+————-+
1 row in set (0.00 sec)

这时可以看到,结果集还是2944条,但是Extra中的filesort不见了。这时mysql使用userid_clicks这个索引去查询,这不但 能快速查询到userid=”admin”的所有记录,并且结果是根据clicks排好序的!所以不用再把这个结果集读入内存一条一条排序了,效率上会高 很多。

但是用多字段索引这种方式有个问题,如果查询的sql种类很多的话,就得好好规划一下了,否则索引会建得非常多,不但会影响到数据insert和update的效率,而且数据表也容易损坏。

以上是对索引优化的办法,因为原因可能会比较复杂,所以写得比较的长,一般好好优化了索引之后,mysql的效率会提升n个档次,从而也不需要考虑增加机器来解决问题了。

但是,mysql甚至所有数据库,可能都不好解决limit的问题。在mysql中,limit 0,10只要索引合适,是没有问题的,但是limit 100000,10就会很慢了,因为mysql会扫描排好序的结果,然后找到100000这个点,取出10条返回。要找到100000这个点,就要扫描 100000条记录,这个循环是比较耗时的。不知道会不会有什么好的算法可以优化这个扫描引擎,我冥思苦想也想不出有什么好办法。对于limit,目前直 至比较久远的将来,我想只能通过业务、程序和数据表的规划来优化,我想到的这些优化办法也都还没有一个是万全之策,往后再讨论。

2、sql写法过于复杂

sql写法假如用到一些特殊的功能,比如groupby、或者多表联合查询的话,mysql用到什么方式来查询也可以用desc来分析,我这边用复杂sql的情况还不算多,所以不常分析,暂时就没有好的建议。

3、配置错误

配置里主要参数是key_buffer、sort_buffer_size/myisam_sort_buffer_size,这两个参数意思是:

key_buffer=128M:全部表的索引都会尽可能放在这块内存区域内,索引比较大的话就开稍大点都可以,我一般设为128M,有个好的建议是把很少用到并且比较大的表想办法移到别的地方去,这样可以显著减少mysql的内存占用。
sort_buffer_size=1M:单个线程使用的用于排序的内存,查询结果集都会放进这内存里,如果比较小,mysql会多放几次,所以稍微开大一点就可以了,重要是优化好索引和查询语句,让他们不要生成太大的结果集。

另外一些配置:
thread_concurrency=8:这个配置标配=cpu数量x2
interactive_timeout=30
wait_timeout=30:这两个配置使用10-30秒就可以了,这样会尽快地释放内存资源,注意:一直在使用的连接是不会断掉的,这个配置只是断掉了长时间不动的连接。
query_cache:这个功能不要使用,现在很多人看到cache这几个字母就像看到了宝贝,这是不唯物主义的。mysql的query_cache 在每次表数据有变化的时候都会重新清理连至该表的所有缓存,如果更新比较频繁,query_cache不但帮不上忙,而且还会对效率影响很大。这个参数只 适合只读型的数据库,如果非要用,也只能用query_cache_type=2自行用SQL_CACHE指定一些sql进行缓存。
max_connections:默认为100,一般情况下是足够用的,但是一般要开大一点,开到400-600就可以了,能超过600的话一般就有效率问题,得另找对策,光靠增加这个数字不是办法。

其它配置可以按默认就可以了,个人觉得问题还不是那么的大,提醒一下:1、配置虽然很重要,但是在绝大部分情况下都不是效率问题的罪魁祸首。2、mysql是一个数据库,对于数据库最重要考究的不应是效率,而是稳定性和数据准确性。

4、机器实在负荷不了

如果做了以上调整,服务器还是不能承受,那就只能通过架构级调整来优化了。

1、mysql同步。

通过mysql同步功能将数据同步到数台从数据库,由主数据库写入,从数据库提供读取。

我个人不是那么乐意使用mysql同步,因为这个办法会增加程序的复杂性,并常常会引起数据方面的错误。在高负荷的服务中,死机了还可以快速重启,但数据错误的话要恢复就比较麻烦。

2、加入缓存

加入缓存之后,就可以解决并发的问题,效果很明显。如果是实时系统,可以考虑用刷新缓存方式使缓存保持最新。

在前端加入squid的架构比较提倡使用,在命中率比较高的应用中,基本上可以解决问题。

如果是在程序逻辑层里面进行缓存,会增加很多复杂性,问题会比较多而且难解决,不建议在这一层面进行调整。

3、程序架构调整,支持同时连接多个数据库

如果web加入缓存后问题还是比较严重,只能通过程序架构调整,把应用拆散,用多台的机器同时提供服务。

如果拆散的话,对业务是有少许影响,如果业务当中有部分功能必须使用所有的数据,可以用一个完整库+n个分散库这样的架构,每次修改都在完整库和分散库各操作一次,或定期整理完整库。

当然,还有一种最笨的,把数据库整个完完整整的做拷贝,然后程序每次都把完整的sql在这些库执行一遍,访问时轮询访问,我认为这样要比mysql同步的方式安全。

4、使用 mysql proxy 代理

mysql proxy 可以通过代理把数据库中的各个表分散到数台服务器,但是它的问题是没有能解决热门表的问题,如果热门内容散在多个表中,用这个办法是比较轻松就能解决问题。

我没有用过这个软件也没有认真查过,不过我对它的功能有一点点怀疑,就是它怎么实现多个表之间的联合查询?如果能实现,那么效率如何呢?

5、使用memcachedb

数据库换用支持mysql的memcachedb,是可以一试的想法,从memcachedb的实现方式和层面来看对数据没有什么影响,不会对用户有什么困扰。

为我现在因为数据库方面问题不多,没有试验过这个玩意。不过,只要它支持mysql的大部分主要的语法,而且本身稳定,可用性是无需置疑的。

FROM:http://www.sudone.com/linux/mysql_debug.html

MySQL的一些变量修改后需要重启数据库,一些参数可以通过SET GLOBAL或SET SESSION进行在线动态修改。

注意:变量中如果是值类型,则一般情况下都是以字节为单位的,因此在设置时一定要将设置的值换算为字节,如:64MB=64*1024*1024=67108864

例:SET GLOBAL read_buffer_size=67108864;

下表列出了MySQL5.1 所有可动态修改的系统参数/变量:

变量名 值类型 类型
autocommit boolean SESSION
big_tables boolean SESSION
binlog_cache_size numeric GLOBAL
bulk_insert_buffer_size numeric GLOBAL | SESSION
character_set_client string GLOBAL | SESSION
character_set_connection string GLOBAL | SESSION
character_set_results string GLOBAL | SESSION
character_set_server string GLOBAL | SESSION
collation_connection string GLOBAL | SESSION
collation_server string GLOBAL | SESSION
completion_type numeric GLOBAL | SESSION
concurrent_insert boolean GLOBAL
connect_timeout numeric GLOBAL
convert_character_set string GLOBAL | SESSION
default_week_format numeric GLOBAL | SESSION
delay_key_write OFF | ON | ALL GLOBAL
delayed_insert_limit numeric GLOBAL
delayed_insert_timeout numeric GLOBAL
delayed_queue_size numeric GLOBAL
div_precision_increment numeric GLOBAL | SESSION
engine_condition_pushdown boolean GLOBAL | SESSION
error_count numeric SESSION
expire_logs_days numeric GLOBAL
flush boolean GLOBAL
flush_time numeric GLOBAL
foreign_key_checks boolean SESSION
ft_boolean_syntax numeric GLOBAL
group_concat_max_len numeric GLOBAL | SESSION
identity numeric SESSION
innodb_autoextend_increment numeric GLOBAL
innodb_concurrency_tickets numeric GLOBAL
innodb_max_dirty_pages_pct numeric GLOBAL
innodb_max_purge_lag numeric GLOBAL
innodb_support_xa boolean GLOBAL | SESSION
innodb_sync_spin_loops numeric GLOBAL
innodb_table_locks boolean GLOBAL | SESSION
innodb_thread_concurrency numeric GLOBAL
innodb_thread_sleep_delay numeric GLOBAL
insert_id boolean SESSION
interactive_timeout numeric GLOBAL | SESSION
join_buffer_size numeric GLOBAL | SESSION
key_buffer_size numeric GLOBAL
last_insert_id numeric SESSION
local_infile boolean GLOBAL
log_warnings numeric GLOBAL
long_query_time numeric GLOBAL | SESSION
low_priority_updates boolean GLOBAL | SESSION
max_allowed_packet numeric GLOBAL | SESSION
max_binlog_cache_size numeric GLOBAL
max_binlog_size numeric GLOBAL
max_connect_errors numeric GLOBAL
max_connections numeric GLOBAL
max_delayed_threads numeric GLOBAL
max_error_count numeric GLOBAL | SESSION
max_heap_table_size numeric GLOBAL | SESSION
max_insert_delayed_threads numeric GLOBAL
max_join_size numeric GLOBAL | SESSION
max_relay_log_size numeric GLOBAL
max_seeks_for_key numeric GLOBAL | SESSION
max_sort_length numeric GLOBAL | SESSION
max_tmp_tables numeric GLOBAL | SESSION
max_user_connections numeric GLOBAL
max_write_lock_count numeric GLOBAL
myisam_stats_method enum GLOBAL | SESSION
multi_read_range numeric GLOBAL | SESSION
myisam_data_pointer_size numeric GLOBAL
log_bin_trust_routine_creators boolean GLOBAL
myisam_max_sort_file_size numeric GLOBAL | SESSION
myisam_repair_threads numeric GLOBAL | SESSION
myisam_sort_buffer_size numeric GLOBAL | SESSION
net_buffer_length numeric GLOBAL | SESSION
net_read_timeout numeric GLOBAL | SESSION
net_retry_count numeric GLOBAL | SESSION
net_write_timeout numeric GLOBAL | SESSION
old_passwords numeric GLOBAL | SESSION
optimizer_prune_level numeric GLOBAL | SESSION
optimizer_search_depth numeric GLOBAL | SESSION
preload_buffer_size numeric GLOBAL | SESSION
query_alloc_block_size numeric GLOBAL | SESSION
query_cache_limit numeric GLOBAL
query_cache_size numeric GLOBAL
query_cache_type enumeration GLOBAL | SESSION
query_cache_wlock_invalidate boolean GLOBAL | SESSION
query_prealloc_size numeric GLOBAL | SESSION
range_alloc_block_size numeric GLOBAL | SESSION
read_buffer_size numeric GLOBAL | SESSION
read_only numeric GLOBAL
read_rnd_buffer_size numeric GLOBAL | SESSION
rpl_recovery_rank numeric GLOBAL
safe_show_database boolean GLOBAL
secure_auth boolean GLOBAL
server_id numeric GLOBAL
slave_compressed_protocol boolean GLOBAL
slave_net_timeout numeric GLOBAL
slave_transaction_retries numeric GLOBAL
slow_launch_time numeric GLOBAL
sort_buffer_size numeric GLOBAL | SESSION
sql_auto_is_null boolean SESSION
sql_big_selects boolean SESSION
sql_big_tables boolean SESSION
sql_buffer_result boolean SESSION
sql_log_bin boolean SESSION
sql_log_off boolean SESSION
sql_log_update boolean SESSION
sql_low_priority_updates boolean GLOBAL | SESSION
sql_max_join_size numeric GLOBAL | SESSION
sql_mode enumeration GLOBAL | SESSION
sql_notes boolean SESSION
sql_quote_show_create boolean SESSION
sql_safe_updates boolean SESSION
sql_select_limit numeric SESSION
sql_slave_skip_counter numeric GLOBAL
updatable_views_with_limit enumeration GLOBAL | SESSION
sql_warnings boolean SESSION
sync_binlog numeric GLOBAL
sync_frm boolean GLOBAL
storage_engine enumeration GLOBAL | SESSION
table_cache numeric GLOBAL
table_type enumeration GLOBAL | SESSION
thread_cache_size numeric GLOBAL
time_zone string GLOBAL | SESSION
timestamp boolean SESSION
tmp_table_size enumeration GLOBAL | SESSION
transaction_alloc_block_size numeric GLOBAL | SESSION
transaction_prealloc_size numeric GLOBAL | SESSION
tx_isolation enumeration GLOBAL | SESSION
unique_checks boolean SESSION
wait_timeout numeric GLOBAL | SESSION
warning_count numeric SESSION

其中:
最后1列说明每个变量是否适用GLOBAL或SESSION(或二者)。
标记为string的变量采用字符串值。标记为numeric的变量采用数字值。标记为boolean的变量可以设置为0、1、ON或OFF。标记为enumeration的变量一般情况应设置为该变量的某个可用值,但还可以设置为对应期望的枚举值的数字。对于枚举系统变量,第1个枚举值应对应0。这不同于ENUM列,第1个枚举值对应1。

本文转自:石展,DBA的视界

网上有很多的文章教怎么配置MySQL服务器,但考虑到服务器硬件配置的不同,具体应用的差别,那些文章的做法只能作为初步设置参考,我们需要根据自己的情况进行配置优化,好的做法是MySQL服务器稳定运行了一段时间后运行,根据服务器的"状态"进行优化。

mysql> show global status;

可以列出MySQL服务器运行各种状态值,另外,查询MySQL服务器配置信息语句:

mysql> show variables;


一、慢查询

mysql> show variables like '%slow%';

image

mysql> show global status like '%slow%';

image

配置中打开了记录慢查询,执行时间超过2秒的即为慢查询,系统显示有4148个慢查询,你可以分析慢查询日志,找出有问题的SQL语句,慢查询时间不宜设置过长,否则意义不大,最好在5秒以内,如果你需要微秒级别的慢查询,可以考虑给MySQL打补丁:http://www.percona.com /docs/wiki/release:start,记得找对应的版本。

"打开慢查询日志可能会对系统性能有一点点影响,如果你的MySQL是主-从结构,可以考虑打开其中一台从服务器的慢查询日志,这样既可以监控慢查询,对系统性能影响又小。"这一段所说的有些问题,如果从服务器只用来同步数据,那么就不涉及到查询的请求。因此更提不到记录慢查询了。

二、连接数

经常会遇见"MySQL: ERROR 1040: Too many connections"的情况,一种是访问量确实很高,MySQL服务器抗不住,这个时候就要考虑增加从服务器分散读压力,另外一种情况是MySQL配置文件中max_connections值过小:

mysql> show variables like 'max_connections';

image 

这台MySQL服务器最大连接数是256,然后查询一下服务器响应的最大连接数:

mysql> show global status like 'Max_used_connections';

MySQL服务器过去的最大连接数是245,没有达到服务器连接数上限256,应该没有出现1040错误,比较理想的设置是:

Max_used_connections / max_connections * 100% ≈ 85%

最大连接数占上限连接数的85%左右,如果发现比例在10%以下,MySQL服务器连接数上限设置的过高了。

三、Key_buffer_size

key_buffer_size是对MyISAM表性能影响最大的一个参数,下面一台以MyISAM为主要存储引擎服务器的配置:

mysql> show variables like 'key_buffer_size';

image

分配了512MB内存给key_buffer_size,我们再看一下key_buffer_size的使用情况:

mysql> show global status like 'key_read%';

image

一共有27813678764个索引读取请求,有6798830个请求在内存中没有找到直接从硬盘读取索引,计算索引未命中缓存的概率:

key_cache_miss_rate = Key_reads / Key_read_requests * 100%

比如上面的数据,key_cache_miss_rate为0.0244%,4000个索引读取请求才有一个直接读硬盘,已经很BT 了,key_cache_miss_rate在0.1%以下都很好(每1000个请求有一个直接读硬盘),如果key_cache_miss_rate在 0.01%以下的话,key_buffer_size分配的过多,可以适当减少。

MySQL服务器还提供了key_blocks_*参数:

mysql> show global status like 'key_blocks_u%';

image

Key_blocks_unused表示未使用的缓存簇(blocks)数,Key_blocks_used表示曾经用到的最大的blocks数,比如这台服务器,所有的缓存都用到了,要么增加key_buffer_size,要么就是过渡索引了,把缓存占满了。比较理想的设置:

Key_blocks_used / (Key_blocks_unused + Key_blocks_used) * 100% ≈ 80%


四、临时表


mysql>
show global status like 'created_tmp%';

image

每次创建临时表,Created_tmp_tables增加,如果是在磁盘上创建临时表,Created_tmp_disk_tables也增加,Created_tmp_files表示MySQL服务创建的临时文件文件数,比较理想的配置是:

Created_tmp_disk_tables / Created_tmp_tables * 100% <= 25%

比如上面的服务器Created_tmp_disk_tables / Created_tmp_tables * 100% = 1.20%,应该相当好了。我们再看一下MySQL服务器对临时表的配置:

mysql> show variables where Variable_name in ('tmp_table_size', 'max_heap_table_size');

image

只有256MB以下的临时表才能全部放内存,超过的就会用到硬盘临时表。


五、Open Table情况

mysql> show global status like 'open%tables%';

image 

Open_tables表示打开表的数量,Opened_tables表示打开过的表数量,如果Opened_tables数量过大,说明配置中 table_cache(5.1.3之后这个值叫做table_open_cache)值可能太小,我们查询一下服务器table_cache值:

mysql> show variables like 'table_open_cache';

image 

比较合适的值为:

Open_tables / Opened_tables * 100% >= 85%

Open_tables / table_open_cache * 100% <= 95%


六、进程使用情况


mysql>
show global status like 'Thread%';

image

如果我们在MySQL服务器配置文件中设置了thread_cache_size,当客户端断开之后,服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁(前提是缓存数未达上限)。Threads_created表示创建过的线程数,如果发现Threads_created值过大的话,表明MySQL服务器一直在创建线程,这也是比较耗资源,可以适当增加配置文件中thread_cache_size值,查询服务器 thread_cache_size配置:

mysql> show variables like 'thread_cache_size';

image 

示例中的服务器还是挺健康的。


七、查询缓存(query cache)

mysql> show global status like 'qcache%';

image 

MySQL查询缓存变量解释:

Qcache_free_blocks:缓存中相邻内存块的个数。数目大说明可能有碎片。FLUSH QUERY CACHE会对缓存中的碎片进行整理,从而得到一个空闲块。

Qcache_free_memory:缓存中的空闲内存。

Qcache_hits:每次查询在缓存中命中时就增大

Qcache_inserts:每次插入一个查询时就增大。命中次数除以插入次数就是不中比率。

Qcache_lowmem_prunes:缓存出现内存不足并且必须要进行清理以便为更多查询提供空间的次数。这个数字最好长时间来看;如果这个数字在不断增长,就表示可能碎片非常严重,或者内存很少。(上面的 free_blocks和free_memory可以告诉您属于哪种情况)

Qcache_not_cached:不适合进行缓存的查询的数量,通常是由于这些查询不是 SELECT 语句或者用了now()之类的函数。

Qcache_queries_in_cache:当前缓存的查询(和响应)的数量。

Qcache_total_blocks:缓存中块的数量。

我们再查询一下服务器关于query_cache的配置:

mysql> show variables like 'query_cache%';

image 

各字段的解释:

query_cache_limit:超过此大小的查询将不缓存

query_cache_min_res_unit:缓存块的最小大小

query_cache_size:查询缓存大小

query_cache_type:缓存类型,决定缓存什么样的查询,示例中表示不缓存 select sql_no_cache 查询

query_cache_wlock_invalidate:当有其他客户端正在对MyISAM表进行写操作时,如果查询在query cache中,是否返回cache结果还是等写操作完成再读表获取结果。

query_cache_min_res_unit的配置是一柄"双刃剑",默认是4KB,设置值大对大数据查询有好处,但如果你的查询都是小数据查询,就容易造成内存碎片和浪费。

查询缓存碎片率 = Qcache_free_blocks / Qcache_total_blocks * 100%

如果查询缓存碎片率超过20%,可以用FLUSH QUERY CACHE整理缓存碎片,或者试试减小query_cache_min_res_unit,如果你的查询都是小数据量的话。

查询缓存利用率 = (query_cache_size - Qcache_free_memory) / query_cache_size * 100%

查询缓存利用率在25%以下的话说明query_cache_size设置的过大,可适当减小;查询缓存利用率在80%以上而且Qcache_lowmem_prunes > 50的话说明query_cache_size可能有点小,要不就是碎片太多。

查询缓存命中率 = (Qcache_hits - Qcache_inserts) / Qcache_hits * 100%

示例服务器 查询缓存碎片率 = 20.46%,查询缓存利用率 = 62.26%,查询缓存命中率 = 1.94%,命中率很差,可能写操作比较频繁吧,而且可能有些碎片。


八、排序使用情况


mysql>
show global status like 'sort%';

image 

Sort_merge_passes 包括两步。MySQL 首先会尝试在内存中做排序,使用的内存大小由系统变量 Sort_buffer_size 决定,如果它的大小不够把所有的记录都读到内存中,MySQL 就会把每次在内存中排序的结果存到临时文件中,等 MySQL 找到所有记录之后,再把临时文件中的记录做一次排序。这再次排序就会增加 Sort_merge_passes。实际上,MySQL 会用另一个临时文件来存再次排序的结果,所以通常会看到 Sort_merge_passes 增加的数值是建临时文件数的两倍。因为用到了临时文件,所以速度可能会比较慢,增加 Sort_buffer_size 会减少 Sort_merge_passes 和 创建临时文件的次数。但盲目的增加 Sort_buffer_size 并不一定能提高速度,见 How fast can you sort data with MySQL?(引自http://qroom.blogspot.com/2007/09/mysql-select-sort.html,貌似被墙)

另外,增加read_rnd_buffer_size(3.2.3是record_rnd_buffer_size)的值对排序的操作也有一点的好处。


九、文件打开数(open_files)


mysql>
show global status like 'open_files';

image 

mysql> show variables like 'open_files_limit';

image 

比较合适的设置:Open_files / open_files_limit * 100% <= 75%


十、表锁情况


mysql>
show global status like 'table_locks%';

image 

Table_locks_immediate表示立即释放表锁数,Table_locks_waited表示需要等待的表锁数,如果 Table_locks_immediate / Table_locks_waited > 5000,最好采用InnoDB引擎,因为InnoDB是行锁而MyISAM是表锁,对于高并发写入的应用InnoDB效果会好些。示例中的服务器Table_locks_immediate / Table_locks_waited = 235,MyISAM就足够了。


十一、表扫描情况


mysql>
show global status like 'handler_read%';

image 
各字段解释参见http://hi.baidu.com/thinkinginlamp/blog/item/31690cd7c4bc5cdaa144df9c.html,调出服务器完成的查询请求次数:

mysql> show global status like 'com_select';

image 

计算表扫描率:

表扫描率 = Handler_read_rnd_next / Com_select

如果表扫描率超过4000,说明进行了太多表扫描,很有可能索引没有建好,增加read_buffer_size值会有一些好处,但最好不要超过8MB。

简介:

该脚本使用 "SHOW STATUS LIKE..." 和 "SHOW VARIABLES LIKE..." 命令获得MySQL相关变量和运行状态。然后根据推荐的调优参数对当前的MySQL数据库进行测试。最后根据不同颜色的标识来提醒用户需要注意的各个参数设置。该版本兼容 MySQL 3.23 和更高版本(包含 5.1)

当前版本会处理如下这些推荐的参数:

Slow Query Log (慢查询日志)
Max Connections (最大连接数)
Worker Threads (工作线程)
Key Buffer (Key 缓冲)
Query Cache (查询缓存)
Sort Buffer (排序缓存)
Joins (连接)
Temp Tables (临时表)
Table (Open & Definition) Cache (表缓存)
Table Locking (表锁定)
Table Scans (read_buffer) (表扫描,读缓冲)
Innodb Status (Innodb 状态)

下载使用:

http://www.day32.com/MySQL/tuning-primer.sh

tuning-primer.sh 有如下运行参数:
Usage: ./tuning-primer.sh [ mode ]

all                    运行所有检测(默认值)
prompt              提示
mem, memory     运行有关内存使用方面的检测
disk, file            运行有关I/O性能和文件处理限制方面的检测
innodb              运行InnoDB检测
misc                 其它

脚本支持my.cnf文件,可以把user, password, host, socket等连接参数放在~/.my.cnf文件里,如果使用了自定义的socket文件,请修改tuning-primer.sh文件中关于socket文件位置的变量。

运行 tuning-primer.sh

SLOW QUERIES

慢查询检查

SLOW QUERIES

The slow query log is enabled.

说明我已经启用了慢查询记录功能。也就是参数
slow_query_log = 1

Current long_query_time = 5.000000 sec.

慢查询的阀值时间。也就是参数
long_query_time = 5

You have 17 out of 638844 that take longer than 5.000000 sec. to complete

说明慢查询日志中记录了17条查询时间超过5秒的语句。
slow_query_log_file=/data/ats_db/mysql-slow.log

设置慢查询日志路径。使用

mysqldumpslow命令查询慢日志

Your long_query_time seems to be fine

慢查询阀值时间设置得在推荐的范围内

BINARY UPDATE LOG

更新二进制日志文件

The binary update log is enabled

这项说明启用了bin-log日志功能。参数
log-bin = /data/ats_db/mysql-bin

Binlog sync is not enabled, you could loose binlog records during a server crash

没有启用 sync_binlog 选项。也即是将二进制日志实时写入到磁盘通过 sync_binlog=1来指定

WORKER THREADS

工作线程

Current thread_cache_size = 8

当前线程缓存大小。
thread_concurrency = 8

Current threads_cached = 7

Show status like 'threads_cached'

Current threads_per_sec = 0

脚本先执行Show status like 'Threads_cached'查看当前的线程创建情况,然后sleep 1后在执行相同的命令,最终后者减去前者的数就是每秒线程创建数。

Historic threads_per_sec = 0

该值是使用Threads_cached /uptime获得的。

Your thread_cache_size is fine

MAX CONNECTIONS

最大连接数

Current max_connections = 1024

当前配置文件中设置的并发连接数

Current threads_connected = 2

当前线程连接诶数。
show status like 'Threads_connected'

Historic max_used_connections = 4

show status like 'Max_used_connections';

The number of used connections is 0% of the configured maximum.

这个值使用 Max_used_connections*100/ max_connections得出。

You are using less than 10% of your configured max_connections.

Lowering max_connections could help to avoid an over-allocation of memory

See "MEMORY USAGE" section to make sure you are not over-allocating

Max_used_connections的值不足max_connections值的10%。设置合适的max_connections值有助于节省内存。

MEMORY USAGE

内存使用

Max Memory Ever Allocated : 841 M

Max Memory Ever Allocated = max_memory

Configured Max Per-thread Buffers : 28.40 G

Configured Max Per-thread Buffers = per_thread_buffers

Configured Max Global Buffers : 586 M

Configured Max Global Buffers = per_thread_max_buffers

Configured Max Memory Limit : 28.97 G

Configured Max Memory Limit = total_memory
这一项很重要,他是将各个缓存的大小累加,然后同max_connections相乘,从而得出当达到max_connections后需要分配的内存有多少。我这里由于max_connections写得很大,造成了最大内存限制超过了真实内存很多,所以建议不要随意增大max_connections的值。减小 max_connections的值,最终保证最大内存限制在真实内存的90%以下。

Physical Memory : 7.79 G

实际物理内存

Max memory limit exceeds 90% of physical memory

per_thread_buffers
(read_buffer_size+read_rnd_buffer_size +sort_buffer_size+thread_stack+
join_buffer_size+binlog_cache_size)*max_connections

per_thread_max_buffers
(read_buffer_size+read_rnd_buffer_size +sort_buffer_size+thread_stack
+join_buffer_size+binlog_cache_size)*max_used_connections

global_buffers
innodb_buffer_pool_size+innodb_additional_mem_pool_size+innodb_log_buffer_size+
key_buffer_size+query_cache_size

max_memory=global_buffers+per_thread_max_buffers

total_memory=global_buffers+per_thread_buffers

KEY BUFFER

Key 缓冲

Current MyISAM index space = 222 K

当前数据库MyISAM表中索引占用磁盘空间

Current key_buffer_size = 512 M

MySQL配置文件中key_buffer_size 设置的大小

Key cache miss rate is 1 : 3316

Key_read_requests/ Key_reads 这里说明3316次读取请求中有1次丢失(也就是说1次读取磁盘)

Key buffer free ratio = 81 %

key_blocks_unused * key_cache_block_size / key_buffer_size * 100

Your key_buffer_size seems to be fine

QUERY CACHE

Query 缓存

Query cache is enabled

该项说明 我们指定了query_cache_size 的值。如果query_cache_size=0的话这里给出的提示是:
Query cache is supported but not enabled
Perhaps you should set the query_cache_size

Current query_cache_size = 64 M

当前系统query_cache_size 值大小 [F]

Current query_cache_used = 1 M

query_cache_used =query_cache_size-qcache_free_memory

Current query_cache_limit = 128 M

变量 query_cache_limit 大小

Current Query cache Memory fill ratio = 1.79 %

query_cache_used/query_cache_size *100%

Current query_cache_min_res_unit = 4 K

show variables like 'query_cache_min_res_unit';

Your query_cache_size seems to be too high.
Perhaps you can use these resources elsewhere

这项给出的结论是query_cache_size的值设置的有些过高。其比对标准是 "Query cache Memory fill ratio"的值如果小于<25%就会给出这个提示。可以将这些资源应用到其他的地方

MySQL won't cache query results that are larger than query_cache_limit in size

MySQL不会将大于query_cache_limit的查询结果进行缓存

show status like 'Qcache%';

Qcache_free_blocks        10       
Qcache_free_memory        65891984    
Qcache_hits            14437       
Qcache_inserts            707        
Qcache_lowmem_prunes    0       
Qcache_not_cached        216        
Qcache_queries_in_cache    540       
Qcache_total_blocks        1191

SORT OPERATIONS

SORT 选项

Current sort_buffer_size = 6 M

show variables like 'sort_buffer%';

Current read_rnd_buffer_size = 16 M

show variables like 'read_rnd_buffer_size%';

Sort buffer seems to be fine

JOINS

JOINS

Current join_buffer_size = 132.00 K

show variables like 'join_buffer_size%';

join_buffer_size= join_buffer_size+4kb

You have had 6 queries where a join could not use an index properly

这里的6是通过 show status like 'Select_full_join'; 获得的

You should enable "log-queries-not-using-indexes"
Then look for non indexed joins in the slow query log.
If you are unable to optimize your queries you may want to increase your
join_buffer_size to accommodate larger joins in one pass.

Note! This script will still suggest raising the join_buffer_size when
ANY joins not using indexes are found.

你需要启用 "log-queries-not-using-indexes" 然后在慢查询日志中看是否有取消索引的joins语句。如果不优化查询语句的话,则需要增大join_buffer_size

OPEN FILES LIMIT

文件打开数限制

Current open_files_limit = 1234 files

show variables like 'open_files_limit%';

The open_files_limit should typically be set to at least 2x-3x

that of table_cache if you have heavy MyISAM usage.

如果系统中有很多的MyISAM类型的表,则建议将open_files_limit 设置为2X~3X的table_open_cache
show status like 'Open_files';

open_files_ratio= open_files*100/open_files_limit
如果open_files_ratio 超过75% 则需要加大open_files_limit

Your open_files_limit value seems to be fine

TABLE CACHE

TABLE 缓存

Current table_open_cache = 512 tables

show variables like 'table_open_cache';

Current table_definition_cache = 256 tables

show variables like ' table_definition_cache ';

You have a total of 368 tables

SELECT

COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'

You have 371 open tables.

show status like 'Open_tables';

The table_cache value seems to be fine

Open_tables /table_open_cache*100% < 95%

You should probably increase your table_definition_cache value.

table_cache_hit_rate =open_tables*100/opened_tables

TEMP TABLES

临时表

Current max_heap_table_size = 16 M

show variables like 'max_heap_table_size';

Current tmp_table_size = 16 M

show variables like 'tmp_table_size';

Of 285 temp tables, 11% were created on disk

Created_tmp_tables=285

created_tmp_disk_tables*100/
(created_tmp_tables+created_tmp_disk_tables)
=11%

Created disk tmp tables ratio seems fine

TABLE SCANS

扫描表

Current read_buffer_size = 6 M

show variables like 'read_buffer_size';

Current table scan ratio = 9 : 1

read_rnd_next =show global status like 'Handler_read_rnd_next';
com_select= show global status like 'Com_select';
full_table_scans=read_rnd_next/com_select
Current table scan ratio = full_table_scans : 1"
如果表扫描率超过4000,说明进行了太多表扫描,很有可能索引没有建好,增加read_buffer_size值会有一些好处,但最好不要超过8MB。

read_buffer_size seems to be fine

TABLE LOCKING

TABLE LOCKING

Current Lock Wait ratio = 0 : 5617

show global status like

'Table_locks_waited';
show global status like

'Questions';
如果 Table_locks_waited=0
Current Lock Wait ratio = 0: Questions

Your table locking seems to be fine

    MySQL启用了binlog 选项后,其数据库所做的修改都会写入到binlog文件中。这样对于数据库基于时间的恢复就变得非常容易。对于比较繁忙的数据库来说,建议组建M-S的结构,然后在Slave上启用log_slave_updates 选项,这样的话Slave在同步Master数据之后会将自己所做的修改写入到binlog日志文件中。这样我们备份slave上的binlog文件也不会影响master数据库的性能。

    建议Slave的配置文件中启用下面几项参数

log_bin                       = /data/mysql_db/mysql-bin
relay-log                    = /data/mysql_db/mysql-relay-bin
log_slave_updates    =  1
sync_binlog               =  1
innodb_support_xa   =  1

 
 

关于参数的解释:

sync_binlog=1 or N

     This makes MySQL synchronize the binary log's contents to disk each time it commits a transaction

     默认情况下,并不是每次写入时都将binlog与硬盘同步。因此如果操作系统或机器(不仅仅是MySQL服务器)崩溃,有可能binlog中最后的语句丢失了。要想防止这种情况,你可以使用sync_binlog全局变量(1是最安全的值,但也是最慢的),使binlog在每Nbinlog写入后与硬盘同步。即使sync_binlog设置为1,出现崩溃时,也有可能表内容和binlog内容之间存在不一致性。如果使用InnoDB表,MySQL服务器处理COMMIT语句,它将整个事务写入binlog并将事务提交到InnoDB中。如果在两次操作之间出现崩溃,重启时,事务被InnoDB回滚,但仍然存在binlog中。可以用--innodb-safe-binlog选项来增加InnoDB表内容和binlog之间的一致性。(注释:在MySQL 5.1中不需要--innodb-safe-binlog;由于引入了XA事务支持,该选项作废了),该选项可以提供更大程度的安全,使每个事务的 binlog(sync_binlog =1)(默认情况为真)InnoDB日志与硬盘同步,该选项的效果是崩溃后重启时,在滚回事务后,MySQL服务器从binlog剪切回滚的 InnoDB事务。这样可以确保binlog反馈InnoDB表的确切数据等,并使从服务器保持与主服务器保持同步(不接收
回滚的语句)

log_slave_updates

    slavemaster获得更新事务后执行同步操作,然后将所做的修改写入到replay-bin-log文件中。这样可以方便的区分slave的更改时来自master还是其他用户或应用程序。当然slave通常是设置为只读的。但还是建议启用slave上的log_slave_updates选项。

innodb_support_xa

    按文档上说支持XA的事务提交分成两步,会有两次写操作。这个选项默认是开的。

二进制日志(Binary Log )格式

    二进制文件时由序列号的事件组成。每个事件都有一个固定大小的标头,其内容包括当前时间戳和默认数据库。可以使用mysqlbinlog工具来查看二进制文件。下面是一段二进制信息的例子:

1     # at 277
2     #071030 10:47:21 server id 3 end_log_pos 369 Query thread_id=13 exec_time=0
       error_code=0
3     SET TIMESTAMP=1193755641/*!*/;
4     insert into test(a) values(2)/*!*/;

第一行
在二进制文件中的偏移字节(这里是 227

第二行
包含了如下的信息:

事件的日期和时间。MySQL使用SET TIMESTAMP 语句生成。

原始的服务器ID,为了防止在多点复制过程中造成无限循环的复制问题

日志结束位置,该值标明了下一个事件的起始便宜字节。

事件类型,这里的例子为
Query
事件类型有很多种。

在原始服务器上执行该事件的的线程ID
执行时间

错误代码

my.cnf参数优化

抢沙发

2009年6月15日 16:23:37

利用 tuning-primer.sh 工具可以实时查看当前mysql的运行情况并给出相应的设置参数。其下载地址:http://www.day32.com/MySQL/tuning-primer.sh运行后的结果为当前系统mysql的运行状态,他会给出相应的建议。

根据tuning-primer.sh的执行结果,所总结的必备参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
[client]
 
 
port = 3306
 
socket = /data/mysql/mysql.sock
 
[mysqld]
 
# MyISAM
 
# 关键词缓冲的大小, 一般用来缓冲MyISAM表的索引块.如果数据库使
#用的是MyISAM表,则建议设置为剩余内存的25-­33% 。
# 不要将其设置大于你可用内存的35%, 因为一部分内存同样被OS用来
#缓冲行数据甚至在你并不使用MyISAM 表的情况下, 你也需要仍旧设置
#起8-64M 内存由于它同样会被内部临时磁盘表使用.
key_buffer_size =256MB
 
# table cache 单位MB
 
# 1G内存以下设置为 256M,1-2G内存设置为 512M 这个参数与
#max_connections 参数互相影响,当增大max_connections值时有必要
#增加table_cache的值。另外table_cache选项在mysql中 对应的变量名
#为table_open_cache。也可以在my.cnf文件中使用 table_open_cache =
#256 来代替 table_cache = 256 通过查看 show status like opend_tables
 
table_cache = 256
 
# =================开启慢查询记录功能=======================
 
slow_query_log = 1
 
# 查询超过这个阀值就记录
 
long-query-time = 5
 
# 记录慢查询的日志文件
 
log-slow-queries = /data/mysqldata/slowquery.log
 
# ===========================================================
 
# ========= 设置二进制日志文件的保存时间 ==========
 
expire_logs_days = 5 # 自动删除5天之前的binlog文件
 
# =================================================
 
log-bin = /data/ats_db/mysql-bin
 
log-error = /data/ats_db/error.log
 
pid-file = /data/ats_db/mysql.pid
 
# ========= 针对Innodb引擎有关的配置 ============
 
# 指定表数据和索引存储的空间,可以是一个或者多个文件。最后
 
# 一个数据文件必须是自动扩充的,也只有最后一个文件允许自动
 
# 扩充。这样,当空间用完后,自动扩充数据文件就会自动增长(
 
# 以8MB为单位)以容纳额外的数据。例如:
 
# innodb_data_file_path=/disk1 /ibdata1:900M;/disk2/ibdata2:50M:autoextend
 
# 两个数据文件放在不同的磁盘上。数据首先放在ibdata1 中,当
 
# 达到900M以后,数据就放在ibdata2中。一旦达到50MB,ibdata2将
 
# 以8MB为单位自动增长。如果磁盘满了,需要在另外的磁盘上面增
 
# 加一个数据文件。
 
innodb_data_file_path = ibdata1:100M:autoextend
 
# innodb的缓冲区大小,用来存放数据和索引,Innodb在线的文档表示
 
# 要设置为机器内存的50%-80%来做这个缓冲区!这个可以说是Innodb
 
# 引擎下配置选项中最关键的参数选项了,对性能的影响也是最大的。
 
innodb_buffer_pool_size = 1024M
 
# 一般16M也够了,可以适当调整下
 
innodb_additional_mem_pool_size = 16M
 
# 25 % of buffer pool size
 
innodb_log_file_size = 256M
 
innodb_log_buffer_size = 16M
 
# Innodb日志提交的方式,0,1,2可供取值,0表示每间隔一秒就写一
 
# 次日志并进行同步,减少了硬盘写操作次数,可以提高性能,1表示每
 
# 执行完 COMMIT就写一次日志并进行同步,默认值,2表示每执行完
#一 次COMMIT写一次日志,每间隔一秒进行一次同步,这个参数在
#Innodb 里同样是关键参数,对性能影响较大。
 
innodb_flush_log_at_trx_commit = 1

安装环境

本次安装MySQL的操作系统选用CentOS5.2,mysql选择5.1.31版本。由于现在的mysql被sun收购,下载免费版本的mysql需要注册,很麻烦,直接到http://linux.softpedia.com/搜索最新的稳定版本下载即可。

准备工作

yum install ncurses-devel gcc-c++ libstdc++-devel
wget ftp://mirror.switch.ch/mirror/mysql/Downloads/MySQL-5.1/mysql-5.1.31.tar.gz
解压 # tar -xvzf msyql-5.1.31.tar.gz

编译安装

# ./configure --prefix=/usr/local/mysql \
--without-debug \
--enable-thread-safe-client \
--enable-assembler \
--enable-profiling \
--with-mysqld-ldflags=-all-static \
--with-client-ldflags=-all-static \
--with-big-tables \
--with-plugins=partition,innobase,myisam \
--with-charset=utf8 \
--with-extra-charsets=gbk,gb2312 \
--with-ssl \
--with-embedded-server

# make && make install
说明:
(1)源码包的编译选项中默认是以Debug模式生成二进制代码。使用编译选项--without-debug 禁用Debug模式编译。
(2)如果把“--with-mysqld-ldflags”和“--with-client-ldflags”两个编译选项设置为“-all-static”的话,可以告诉编译器以静态方式编译使编译结果代码得到最高的性能。使用静态编译和使用动态编译的代码相比,性能差距可能会达到5%~10%之多。
(3)“--with-plugins” 选项可以根据自己的需要编译相应的数据库插件。这些插件可以在编译完成后手动添加和删除。

将mysql的lib文件加载到系统变量中

# vi /etc/ld.so.conf
/usr/local/mysql/lib/mysql

# ldconfig -v | grep mysql
/usr/local/mysql/lib/mysql:
libmysqlclient.so.16 -> libmysqlclient.so.16.0.0
libmysqlclient_r.so.16 -> libmysqlclient_r.so.16.0.0

显示上面信息代表系统加载mysql的lib库正常

创建mysql用户

# useradd -s /sbin/nologin -c 'mysql user' mysql
将安装目录权限修改为mysql
# chown -R mysql.mysql /usr/local/mysql
将对应的配置文件复制到/etc/目录下
# cd /usr/local/mysql/share/mysql
# cp my-huge.cnf /etc/my.cnf

编辑my.cnf文件,配置相关参数,结果如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# The MySQL Client
[client]
port		= 3306
socket		= /data/ats_db/mysql.sock
 
[mysql]
prompt="\u@db001 [\d] &gt;"
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates
 
# The MySQL server
[mysqld]
port		= 3306
socket		= /data/ats_db/mysql.sock
datadir         = /data/ats_db
skip-locking
key_buffer = 512M
max_allowed_packet = 4M
table_cache = 512
sort_buffer_size = 6M
read_buffer_size = 6M
read_rnd_buffer_size = 16M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size = 256M
query_cache_limit = 384M
 
# Try number of CPU's*2 for thread_concurrency
thread_concurrency = 8
 
open_files_limit	= 2000
table_open_cache	= 1024
table_definition_cache	= 512
tmp_table_size		= 64M
max_heap_table_size	= 64M
skip-name-resolve
back_log = 512
 
max_connections 	= 150
max_connect_errors 	= 500
wait_timeout 		= 10
 
#skip-networking
 
# Disable Federated by default
#skip-federated
 
# bin log
expire_logs_days	= 5
sync_binlog		= 0
log-bin			= /data/ats_db/mysql-bin
binlog_format		= mixed
#binlog-ignore-db	= information_schema,mysql
log-error		= /data/ats_db/error.log
pid-file		= /data/ats_db/mysql.pid
 
# 启用慢查询记录功能
slow_query_log		= 1
long_query_time		= 5
slow_query_log_file	= /data/ats_db/mysql-slow.log
 
server-id		= 11
 
# Innodb Configure
innodb_data_home_dir	= /data/ats_db
 
innodb_data_file_path	= ibdata1:1024M;ibdata2:100M:autoextend
 
innodb_buffer_pool_size		= 2048M
innodb_additional_mem_pool_size = 16M
# 25 % of buffer pool size
innodb_log_file_size = 256M
innodb_log_files_in_group = 3
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit	= 2
 
[mysqldump]
quick
max_allowed_packet = 16M
 
[isamchk]
key_buffer = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M
 
[myisamchk]
key_buffer = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M
 
[mysqlhotcopy]
interactive-timeout

生成默认数据库

# mkdir /data/ats_db
# /usr/local/mysql/bin/mysql_install_db --user=mysql

将默认数据库的权限修改为mysql
# cd /data/
# chown -R mysql.mysql ats_db

安装完毕收尾工作

# ln -s /usr/local/mysql/bin/* /usr/local/bin
# ln -s /usr/local/mysql/libexec/* /usr/local/libexec
# ln -s /usr/local/mysql/share/man/man1/* /usr/share/man/man1
# ln -s /usr/local/mysql/share/man/man8/* /usr/share/man/man8

将mysql作为系统服务随系统启动

# cp /usr/local/mysql/share/mysql/mysql.server /etc/rc.d/init.d/mysqld
# chkconfig --add mysqld
# chkconfig mysqld on

启动mysql
# mysqld_safe &

# service mysqld start

如果报错,查看/data/ats_db/error.log文件排查问题

基本的MySQL安全设置

安装完mysql后,其bin目录下有一个mysql_secure_installation 脚本,用来设置mysql
最基本的安全选项,其做了如下操作:

(1)设置本地root用户登陆的密码(默认情况下本地root登陆是不需要密码的)
(2)删除anonymous 匿名用户
(3)禁止ront远程访问数据库
(4)删除默认test数据库,这个数据库也没什么用只是测试anonymous 用户登陆之用。
(5)这一步是最后一步,更新权限表,然后退出。

操作步骤如下所示:

# ln -s /data/ats_db/mysql.sock /tmp/
# /usr/local/mysql/bin/mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MySQL to secure it, we'll need the current
password for the root user.  If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none): # 这一步输入当前root密码默认空,回车即可
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.

Set root password? [Y/n] Y       # 是否设置root密码
New password:                    # 设置root密码
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!

By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] Y # 是否移除匿名用户
... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] Y # 是否禁止root远程访问
... Success!

By default, MySQL comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] Y # 是否删除test数据库
- Dropping test database...
... Success!

- Removing privileges on test database...
... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] Y # 是否更新权限表,如果不更新则前面的操作都无效
... Success!

Cleaning up...
All done!  If you've completed all of the above steps, your MySQL
installation should now be secure.
Thanks for using MySQL!

查看数据目录下的文件

ll /data/ats_db

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-rw-rw---- 1 mysql root      2041 Feb 12 16:57 error.log
-rw-rw---- 1 mysql mysql 10485760 Feb 12 16:56 ibdata1
-rw-rw---- 1 mysql mysql  5242880 Feb 12 16:57 ib_logfile0
-rw-rw---- 1 mysql mysql  5242880 Feb 12 15:29 ib_logfile1
drwx------ 2 mysql mysql     4096 Feb 12 15:27 mysql
-rw-rw---- 1 mysql mysql    18902 Feb 12 15:27 mysql-bin.000001
-rw-rw---- 1 mysql mysql   704189 Feb 12 15:27 mysql-bin.000002
-rw-rw---- 1 mysql mysql      125 Feb 12 15:33 mysql-bin.000003
-rw-rw---- 1 mysql mysql      125 Feb 12 16:49 mysql-bin.000004
-rw-rw---- 1 mysql mysql      125 Feb 12 16:56 mysql-bin.000005
-rw-rw---- 1 mysql mysql      125 Feb 12 16:56 mysql-bin.000006
-rw-rw---- 1 mysql mysql      106 Feb 12 16:57 mysql-bin.000007
-rw-rw---- 1 mysql mysql      203 Feb 12 16:57 mysql-bin.index
-rw-rw---- 1 mysql mysql        6 Feb 12 16:57 mysql.pid
srwxrwxrwx 1 mysql mysql        0 Feb 12 16:57 mysql.sock
drwx------ 2 mysql mysql     4096 Feb 12 15:27 test