手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表Tag:mysql

mysql命令行常用命令

这是某人整理的东西,发现还是挺有用的。。

它来自于PHP博客,看着挺有用。值得摘抄

mysql命令行常用命令

第一招、mysql服务的启动和停止
net stop mysql
net start mysql

第二招、登陆mysql
语法如下: mysql -u用户名 -p用户密码
键入命令mysql -uroot -p, 回车后提示你输入密码,输入12345,然后回车即可进入到mysql中了,mysql的提示符是:
mysql>
注意,如果是连接到另外的机器上,则需要加入一个参数-h机器IP

第三招、增加新用户
格式:grant 权限 on  数据库.* to 用户名@登录主机 identified by "密码"
如,增加一个用户user1密码为password1,让其可以在本机上登录, 并对所有数据库有查询、插入、修改、删除的权限。首先用以root用户连入mysql,然后键入以下命令:
grant select,insert,update,delete on *.* to user1@localhost Identified by "password1";
如果希望该用户能够在任何机器上登陆mysql,则将localhost改为"%"。
如果你不想user1有密码,可以再打一个命令将密码去掉。
grant select,insert,update,delete on mydb.* to user1@localhost identified by "";

第四招: 操作数据库
登录到mysql中,然后在mysql的提示符下运行下列命令,每个命令以分号结束。
1、 显示数据库列表。
show databases;
缺省有两个数据库:mysql和test。 mysql库存放着mysql的系统和用户权限信息,我们改密码和新增用户,实际上就是对这个库进行操作。
2、 显示库中的数据表:
use mysql;
show tables;
3、 显示数据表的结构:
describe 表名;
4、 建库与删库:
create database 库名;
drop database 库名;
5、 建表:
use 库名;
create table 表名(字段列表);
drop table 表名;
6、 清空表中记录:
delete from 表名;
7、 显示表中的记录:
select * from 表名;

第五招、导出和导入数据
1. 导出数据:
mysqldump --opt test > mysql.test
即将数据库test数据库导出到mysql.test文件,后者是一个文本文件
如:mysqldump -u root -p123456 --databases dbname > mysql.dbname
就是把数据库dbname导出到文件mysql.dbname中。
2. 导入数据:
mysqlimport -u root -p123456 < mysql.dbname。
不用解释了吧。
3. 将文本数据导入数据库:
文本数据的字段数据之间用tab键隔开。
use test;
load data local infile "文件名" into table 表名;

 

MySQL 包括一个服务器进程管理数据库,以及一系列访问数据库和创建应用的工具:

mysql               : 在 MySQL 中执行 SQL 查询,也可以执行在文件中存储的SQL命令;
mysqlaccess  : 管理用户;
mysqladmin   : 管理数据库服务器,包括数据库的创建和移除;
mysqld            : 实际的 MySQL 服务器进程;
mysqldump    : 将数据库或表的定义和内容转储到文件;
mysqlhotcopy : 热备份;
mysqlimport   : 将不同文件格式的数据导入到 MySQL 表中;
mysqlshow    : 显示服务器或者任何对象(数据库和表)的信息。

mysql_secure_installation  :  用于管理 root 密码,远程访问、移除临时(测试)数据库及临时用户的一个脚本。

一般来讲,Root 应只用于数据库本机上登录 MySQL,我们可以增加一个拥有超级管理权限的用户 'admin' 来实现远程的维护。

Tips:

1、用 root 登录;(在命令行键入:mysql -u用户名 -p密码)
2、执行如下语句:
   mysql>grant all privilages on *.* to admin@localhost identified by 'password' with grant option;
   mysql>grant all privilages on *.* to admin@"%" identified by 'password' with grant option;

   "%"是通配符,授予 admin 用户可以从任何主机发起访问,password 是为 admin 用户设置的密码。

===============================================

mysql命令行常用命令

mysql命令行常用命令

第一招、mysql服务的启动和停止
net stop mysql
net start mysql

第二招、登陆mysql
语法如下: mysql -u用户名 -p用户密码
键入命令mysql -uroot -p, 回车后提示你输入密码,输入12345,然后回车即可进入到mysql中了,mysql的提示符是:
mysql>
注意,如果是连接到另外的机器上,则需要加入一个参数-h机器IP

第三招、增加新用户
格式:grant 权限 on 数据库.* to 用户名@登录主机 identified by "密码"
如,增加一个用户user1密码为password1,让其可以在本机上登录, 并对所有数据库有查询、插入、修改、删除的权限。首先用以root用户连入mysql,然后键入以下命令:
grant select,insert,update,delete on *.* to user1@localhost Identified by "password1";
如果希望该用户能够在任何机器上登陆mysql,则将localhost改为"%"。
如果你不想user1有密码,可以再打一个命令将密码去掉。
grant select,insert,update,delete on mydb.* to user1@localhost identified by "";

第四招: 操作数据库
登录到mysql中,然后在mysql的提示符下运行下列命令,每个命令以分号结束。
1、 显示数据库列表。
show databases;
缺省有两个数据库:mysql和test。 mysql库存放着mysql的系统和用户权限信息,我们改密码和新增用户,实际上就是对这个库进行操作。
2、 显示库中的数据表:
use mysql;
show tables;
3、 显示数据表的结构:
describe 表名;
4、 建库与删库:
create database 库名;
drop database 库名;
5、 建表:
use 库名;
create table 表名(字段列表);
drop table 表名;
6、 清空表中记录:
delete from 表名;
7、 显示表中的记录:
select * from 表名;

第五招、导出和导入数据
1. 导出数据:
mysqldump --opt test > mysql.test
即将数据库test数据库导出到mysql.test文件,后者是一个文本文件
如:mysqldump -u root -p123456 --databases dbname > mysql.dbname
就是把数据库dbname导出到文件mysql.dbname中。
2. 导入数据:
mysqlimport -u root -p123456 < mysql.dbname。
不用解释了吧。
3. 将文本数据导入数据库:
文本数据的字段数据之间用tab键隔开。
use test;
load data local infile "文件名" into table 表名;

 第六招、执行外部脚本文件

mysql - u test - p1234 --database BugFree < D:/GreenAMP/BugFree.sql

Tags: mysql

discuz数据表优化

这是来自imysql.cn的文章,作者是叶金荣,第一部分内容是3年前的了。可略作参考,估计7.0的数据库应该已经部分解决这个问题,第二部分是最新的。或许也能帮助你解决一些问题。

对于我来说是不用的啦。。我的论坛才几十个人。根本不需要用到这些功能。哇哈哈哈。
不过,我记得,如果是自己的服务器架设的论坛,DZ可以通过打开APC来进行缓存加速(好象是6.X版本中的功能。7.X没有研究过是不是还存在)

不说废话,看叶金荣先生的文章:


第一部分:

一. 前言
近日由于需要,对discuz论坛(简称dz)进行优化,当然了,只是涉及到数据库的优化.
先说一下服务器及dz的数据量,2 * Intel(R) Xeon(TM) CPU 2.40GHz, 4GB mem, SCISC硬盘.
MySQL 版本为 4.0.23. 数据表情况:
cdb_attachments 2万
cdb_members 10万
cdb_posts 68万
cdb_threads 7万
二. 缓存优化
在 my.cnf 中添加/修改以下选项:

#取消文件系统的外部锁
skip-locking
#不进行域名反解析,注意由此带来的权限/授权问题
skip-name-resolve
#索引缓存,根据内存大小而定,如果是独立的db服务器,可以设置高达80%的内存总量
key_buffer = 512M
#连接排队列表总数
back_log = 200
max_allowed_packet = 2M
#打开表缓存总数,可以避免频繁的打开数据表产生的开销
table_cache = 512
#每个线程排序所需的缓冲
sort_buffer_size = 4M
#每个线程读取索引所需的缓冲
read_buffer_size = 4M
#MyISAM表发生变化时重新排序所需的缓冲
myisam_sort_buffer_size = 64M
#缓存可重用的线程数
thread_cache = 128
#查询结果缓存
query_cache_size = 128M
#设置超时时间,能避免长连接
set-variable = wait_timeout=60
#最大并发线程数,cpu数量*2
thread_concurrency = 4
#记录慢查询,然后对慢查询一一优化
log-slow-queries = slow.log
long_query_time = 1
#关闭不需要的表类型,如果你需要,就不要加上这个
skip-bdb

以上参数根据各自服务器的配置差异进行调整,仅作为参考.
三. 索引优化
上面提到了,已经开启了慢查询,那么接下来就要对慢查询进行逐个优化了.
1. 搜索优化
搜索的查询SQL大致如下:

SELECT t.* FROM cdb_posts p, cdb_threads t WHERE
t.fid IN ('37', '45', '4', '6', '17', '41', '28', '32', '31', '1', '42')
AND p.tid=t.tid AND p.author LIKE 'JoansWin'
GROUP BY t.tid ORDER BY lastpost DESC LIMIT 0, 80;

用 EXPLAIN 分析的结果如下:

mysql>EXPLAIN  SELECT t.* FROM cdb_posts p, cdb_threads t WHERE
t.fid IN ('37', '45', '4', '6', '17', '41', '28', '32', '31', '1', '42')
AND p.tid=t.tid AND p.author LIKE 'JoansWin'
GROUP BY t.tid ORDER BY lastpost DESC LIMIT 0, 80;
+-----------+------------+----------+--------------+-------------+-----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
+-----------+------------+----------+--------------+-------------+-----------+-------------+
| 1 | SIMPLE | t | range | PRIMARY,fid | fid | 2 | NULL | 66160 | Using where;
Using temporary; Using filesort |
| 1 | SIMPLE | p | ref | tid | tid | 3 | Forum.t.tid | 10 | Using where
| +----+-------------+-------+-------+---------------+------+---------+-------------+-------+
---------

只用到了 t.fidp.tid,而 p.author 则没有索引可用,总共需要扫描
66160*10 = 661600 次索引,够夸张吧 :(
再分析 cdb_threadscdb_posts 的索引情况:

mysql>show index from cdb_posts; 
+-----------+------------+----------+--------------+-------------+-----------+----------
---+----------+--------+------+--+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part |
Packed | Null | Index_type | Comment | +-----------+------------+----------+--------------+----
---------+-----------+-------------+----------+--------+------+--+
| cdb_posts | 0 | PRIMARY | 1 | pid | A | 680114 | NULL | NULL |
| BTREE | |
| cdb_posts | 1 | fid | 1 | fid | A | 10 | NULL | NULL |
| BTREE | |
| cdb_posts | 1 | tid | 1 | tid | A | 68011 | NULL | NULL |
| BTREE | |
| cdb_posts | 1 | tid | 2 | dateline | A | 680114 | NULL | NULL |
| BTREE | |
| cdb_posts | 1 | dateline | 1 | dateline | A | 680114 | NULL | NULL |
| BTREE | |
+-----------+------------+----------+--------------+-------------+-----------+---

以及

mysql>show index from cdb_threads; 
+-----------+------------+----------+--------------+-------------+-----------+-------------+
----------+--------+------+-----+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part |
Packed | Null | Index_type | Comment | +-----------+------------+----------+--------------+-----
--------+-----------+-------------+----------+--------+------+-----+
| cdb_threads | 0 | PRIMARY | 1 | tid | A | 68480 | NULL | NULL |
| BTREE | |
| cdb_threads | 1 | lastpost | 1 | topped | A | 4 | NULL | NULL |
| BTREE | |
| cdb_threads | 1 | lastpost | 2 | lastpost | A | 68480 | NULL | NULL |
| BTREE | |
| cdb_threads | 1 | lastpost | 3 | fid | A | 68480 | NULL | NULL |
| BTREE | |
| cdb_threads | 1 | replies | 1 | replies | A | 233 | NULL | NULL |
| BTREE | |
| cdb_threads | 1 | dateline | 1 | dateline | A | 68480 | NULL | NULL |
| BTREE | |
| cdb_threads | 1 | fid | 1 | fid | A | 10 | NULL | NULL |
| BTREE | |
| cdb_threads | 1 | enablehot | 1 | enablehot | A | 2 | NULL | NULL |
| BTREE | | +-------------+------------+-----------+--------------+-------------+------

看到索引 fidenablehot 基数太小,看来该索引完全没必要,不过,对于fid基数较大的情况,则可能需要保留>该索引.
所做修改如下:

ALTER TABLE `cdb_threads` DROP INDEX `enablehot`, DROP INDEX `fid`, ADD INDEX (`fid`, `lastpost`);
ALTER TABLE `cdb_posts` DROP INDEX `fid`, ADD INDEX (`author`(10));
OPTIMIZE TABLE `cdb_posts`;
OPTIMIZE TABLE `cdb_threads`;

在这里, p.author 字段我设定的部分索引长度是 10, 是我经过分析后得出来的结果,不同的系统,这里的长度也不同,最好自己先取一下平均值,然后再适当调整.
现在,再来执行一次上面的慢查询,发现时间已经从 6s 变成 0.19s,提高了 30 倍.
这次先到这里,下次继续 ^_^


第二部分:

很早以前写过一个文章,是关于discuz论坛的优化:MySQL优化 之 Discuz论坛优化。 写的时候是2006年,没想到过了这么久,discuz论坛的问题还是困扰着很多网友,其实从各论坛里看到的问题总结出来,很关键的一点都是因为没有将数 据表引擎转成InnoDB导致的,discuz在并发稍微高一点的环境下就表现的非常糟糕,产生大量的锁等待,这时候如果把数据表引擎改成InnoDB的 话,我相信会好很多。这次就写个扫盲贴吧。

1. 启用innodb引擎,并配置相关参数

#skip-innodb
innodb_additional_mem_pool_size = 16M #一般16M也够了,可以适当调整下
innodb_buffer_pool_size = 6G #如果是专用db的话,一般是内存总量的80%
innodb_data_file_path = ibdata1:1024M:autoextend
innodb_file_io_threads = 4
innodb_thread_concurrency = 20
innodb_flush_log_at_trx_commit = 1
innodb_log_buffer_size = 16M
innodb_log_file_size = 256M
innodb_log_files_in_group = 3
innodb_max_dirty_pages_pct = 50
innodb_lock_wait_timeout = 120
innodb_file_per_table

2. 修改表引擎为innodb

mysql> alter table cdb_access engine = innodb;

其他表类似上面,把表名换一下即可...
将表存储引擎改成innodb后,不仅可以避免大量的锁等待,还可以提升查询的效率,因为innodb会把data和index都放在buffer pool中,效率更高。

 


膘叔认为:如果有自己的服务器,可以考虑做几件事情
1、如果有APC功能打开APC
2、如果没有APC,可以考虑把缓存目录指定为内存看看
3、GZIP关闭,少用rewrite等
4、在大负载的情况下,又只有一台服务器,考虑改程序,延迟插入或者其他的。。。(不太现实,哈哈)

 

Tags: discuz, mysql, innodb

关于mysql 1366的错误。

在查mysql 1366的错误原因时,发现一些有趣的回答。地址为:http://zhidao.baidu.com/question/59029575.html

不过,还是有人给出了比较好的解决方法:

  1. MySQL 1366错误大致描述如下  
  2.   
  3.    1. SQL Error: 1366: Incorrect string value: "\xE8\xAF\xA6\xE7\xBB\x86…" for column "address" at row 1  
  4.   
  5. 解决办法:检查数据库此字段的字符集与整理字符集是否与SQL语句传递数据的字符集相同;不相同则会引发MySQL1366错误。  
  6.   
  7. 修改MySQL该字段的字符集与整理规则即可。假设数据表为phplamp, SQL语句的字符集为utf8,出错的字段为address:  
  8. MySQL 1366 错误解决办法  
  9.   
  10.    1. #检查数据表所有字段的状态  
  11.    2. ->show full columns from phplamp;  
  12.    3. #发现address字段的Collation项非utf8,修改它!  
  13.    4. ->alter table phplamp change name name varchar(100) character set utf8 collate utf8_unicode_ci not null default '';  
  14.   
  15. 修改完字段的字符集后可以再使用show full columns from table_name命令检查一下,以确保万无一失。假如您的SQL字符集为GBK或是GB2312或是其它的话,只需要将数据表字段的字符集更改为其相应的编码即可。  
  16.   
  17. 再送上一个MySQL的命令:  
  18. 修改数据表的字符集与整理  
  19.   
  20.    1. ->show full columns from table_name;  

 

Tags: mysql, 1366

mssql和mysql区别

偶尔看到这篇文章,觉得转下来也挺不错。毕竟现在mssql用的人也挺多,不是吗?
数据库迁移问题也可以多注意一下。。

原文地址:
内容如下:http://www.cnblogs.com/perfectdesign/archive/2009/05/22/mssql2mysql.html

最近在做mssql转换成mysql的工作,总结了点经验,跟大家分享一下。

同时这些也会在不断更新。也希望大家补充。

 

1 mysql支持enum,set类型,sql server不支持

2 mysql不支持nchar,nvarchar,ntext类型

3 mysql的递增语句是AUTO_INCREMENT,而mssqlidentity(1,1)

4 msms默认到处表创建语句的默认值表示是((0)),而在mysql里面是不允许带两括号的

5 mysql需要为表指定存储类型

6 mssql识别符是[],[type]表示他区别于关键字,但是mysql却是 `,也就是按键1左边的那个符号

7 mssql支持getdate()方法获取当前时间日期,但是mysql里面可以分日期类型和时间类型,获取当前日期是cur_date(),当前完整时间是 now()函数

8 mssql不支持replace into 语句,但是在最新的sql20008里面,也支持merge语法

9 mysql支持insert into table1 set t1 = ‘’, t2 = ‘’ ,但是mssql不支持这样写

10 mysql支持insert into tabl1 values (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,1)

11 mssql不支持limit语句,是非常遗憾的,只能用top 取代limt 0,Nrow_number() over()函数取代limit N,M

12 mysql在创建表时要为每个表指定一个存储引擎类型,而mssql只支持一种存储引擎

13 mysql不支持默认值为当前时间的datetime类型(mssql很容易做到),在mysql里面是用timestamp类型

14 mssql里面检查是否有这个表再删除,需要这样:

if   exists   (select   *   from   dbo.sysobjects   where   id   =   object_id(N'uc_newpm')   and   OBJECTPROPERTY(id,   N'IsUserTable')   =   1) 

但是在mysql里面只需要 DROP TABLE IF EXISTS cdb_forums;

15 mysql支持无符号型的整数,那么比不支持无符号型的mssql就能多出一倍的最大数存储

16 mysql不支持在mssql里面使用非常方便的varchar(max)类型,这个类型在mssql里面既可做一般数据存储,也可以做blob数据存储

17 mysql创建非聚集索引只需要在创建表的时候指定为key就行,比如:KEY displayorder (fid,displayorder) mssql里面必须要:create unique nonclustered index index_uc_protectedmembers_username_appid on dbo.uc_protectedmembers

(username asc,appid asc)


18 mysql text字段类型不允许有默认值

19mysql的一个表的总共字段长度不超过65XXX

20一个很表面的区别就是mysql的安装特别简单,而且文件大小才110M(非安装版),相比微软这个庞然大物,安装进度来说简直就是.....

21mysql的管理工具有几个比较好的,mysql_front,和官方那个套件,不过都没有SSMS的使用方便,这是mysql很大的一个缺点。

22mysql的存储过程只是出现在最新的版本中,稳定性和性能可能不如mssql。

23 同样的负载压力,mysql要消耗更少的CPU和内存,mssql的确是很耗资源。

24php连接mysql和mssql的方式都差不多,只需要将函数的mysql替换成mssql即可。

25mysql支持date,time,year类型,mssql到2008才支持date和time。

Tags: mssql, mysql

mysql性能的检查和优化方法

原文地址:http://www.artbeta.com/bbs/thread-817-1-1.html

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的大部分主要的语法,而且本身稳定,可用性是无需置疑的。

Tags: mysql, 优化