[关闭]
@xxliixin1993 2016-06-04T14:10:53.000000Z 字数 8965 阅读 2084

学习MySQL笔记

参考:http://doc.mysql.cn/mysql5/refman-5.1-zh.html-chapter/
database


1 MySQL用户账户管理

1.1 创建新用户的方式

  1. GRANT SELECT, INSERT ON *.* TO 'lixin'@'%';
  2. GRANT ALL ON *.* TO 'lixin'@'%';
  3. <font color='red'>注意:</font>用以上命令授权的用户没有给其它用户授权的权限,如果想让该用户可以授权,用以下命令:
  4. GRANT privileges ON databasename.tablename TO 'username'@'host' **WITH GRANT OPTION**;
  1. mysql> INSERT INTO user
  2. -> VALUES('localhost','monty',PASSWORD('some_pass'),
  3. -> 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
  4. mysql> INSERT INTO user
  5. -> VALUES('%','monty',PASSWORD('some_pass'),
  6. -> 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
  7. mysql> INSERT INTO user SET Host='localhost',User='admin',
  8. -> Reload_priv='Y', Process_priv='Y';
  9. mysql> INSERT INTO user (Host,User,Password)
  10. -> VALUES('localhost','dummy','');
  11. mysql> FLUSH PRIVILEGES;

区别:
1. 当你用INSERT创建账户时使用FLUSH PRIVILEGES的原因是告诉服务器重读授权表。否则,只有重启服务器后更改方会被注意到。使用 GRANT,则不需要使用FLUSH PRIVILEGES。
2. 用INSERT使用PASSWORD()函数是为了加密密码。GRANT语句为你加密密码,因此不需要PASSWORD()。

最好的方法是使用GRANT语句,因为这样更精确,错误少。

1.2 限制账户连接资源

限制MySQL服务器资源使用的一个方法是将max_user_connections系统变量设置为非零值。但是,该方法严格限于全局,不允许管理具体账户。并且,它只限制使用单一账户同时连接的数量,而不是客户端连接后的操作。

在MySQL 5中,你可以为具体账户限制下面的服务器资源:
+ 账户每小时可以发出的查询数
+ 账户每小时可以发出的更新数
+ 账户每小时可以连接服务器的次数

资源限制保存在max_questionsmax_updatesmax_connectionsmax_user_connections列内。如果user表没有这些列,必须对它进行升级;
例如

  1. mysql> GRANT ALL ON customer.* TO 'francis'@'localhost'
  2. -> IDENTIFIED BY 'frank'
  3. -> WITH MAX_QUERIES_PER_HOUR 20 /*每小时最大查询次数*/
  4. -> MAX_UPDATES_PER_HOUR 10 /*每小时最大更新次数*/
  5. -> MAX_CONNECTIONS_PER_HOUR 5 /*账号每小时最大连接次数*/
  6. -> MAX_USER_CONNECTIONS 2; /*账户一次可以同时连接的最大连接数*/
  7. 要想取消已有限制,将该值设置为零

2 MySQL数据库备份

  1. 导入:
  2. 1)mysql> USE 数据库名; [数据库要事先存在]
  3. mysql> SOURCE d:/test.sql;
  4. 2) [数据库要事先存在]
  5. mysqldump --default-character-set=utf8 -u用户名 -p 数据库名 < 目标文件(如d:\test.sql)
  6. 导出:
  7. mysqldump --default-character-set=utf8 -u用户名 -p 数据库名 > 目标文件(如d:\test.sql)
  8. mysqldump -u root -p tpweb > d:\test.sql

参考 http://xxlixin1993.blog.51cto.com/9498220/1664432
补充:

  1. 指定恢复时间
  2. mysqlbinlog --stop-date="2005-04-20 9:59:59" /var/log/mysql/bin.123456 | mysql -u root -pmypwd
  3. 指定恢复位置
  4. mysqlbinlog --start-position="368315" /var/log/mysql/bin.123456 | mysql -u root -pmypwd

3 编码

查看当前编码:

show variables like 'character%';
1.改配置文件并重启 /etc/my.ini

  1. [mysqld]
  2. default-character-set = utf8
  3. character_set_server = utf8
  4. [client]
  5. default-character-set=utf8
  6. [mysql]
  7. default-character-set = utf8
  8. [mysqld_safe]
  9. default-character-set = utf8
  10. [mysql.server]
  11. default-character-set = utf8
  12. <div class="md-section-divider"></div>

2.立即生效 但重启服务会失效

  1. SET character_set_client = utf8;
  2. SET character_set_results = utf8;
  3. SET character_set_connection = utf8;
  4. <div class="md-section-divider"></div>

4 MySQL中的复制

4.1 主从复制原理

复制过程中一个服务器充当主服务器,一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,然后封锁并等待主服务器通知新的更新。

主从复制的优点:
1. 主服务器/从服务器设置增加了健壮性。主服务器出现问题时,你可以切换到从服务器作为备份。
2. 通过在主服务器和从服务器之间切分处理客户查询的负荷,可以得到更好的客户响应时间。读操作调度给slave,写操作调度给master
3. 使用复制的另一个好处是可以使用一个从服务器执行备份,而不会干扰主服务器。

4.1 主从复制实施

参考 http://xxlixin1993.blog.51cto.com/9498220/1664432
MySQL复制基于主服务器在二进制日志中跟踪所有对数据库的更改(更新、删除等等)。因此,要进行复制,必须在主服务器上启用二进制日志。每个从服务器从主服务器接收主服务器已经记录到其二进制日志的保存的更新,以便从服务器可以对其数据拷贝执行相同的更新。

细节
MySQL使用3个线程来执行复制功能(其中1个在主服务器上,另两个在从服务器上。当发出START SLAVE时,从服务器创建一个I/O线程,以连接主服务器并让它发送记录在其二进制日志中的语句。主服务器创建一个线程将二进制日志中的内容发送到从服务器。该线程可以识别为主服务器上SHOW PROCESSLIST的输出中的Binlog Dump线程。从服务器I/O线程读取主服务器Binlog Dump线程发送的内容并将该数据拷贝到从服务器数据目录中的本地文件中,即中继日志。第3个线程是SQL线程,是从服务器创建用于读取中继日志并执行日志中包含的更新。

5 优化

优化的前提是知道瓶颈的所在。所有做基准测试是非常有必要的。推荐工具sysbench。
最常见的系统瓶颈是:磁盘搜索,磁盘读/写,CPU周期(我们将数据读入内存后,需要对它进行处理以获得我们需要的结果。表相对于内存较小是最常见的限制因素。当CPU需要的数据超出CPU缓存时,主缓存带宽就成为内存的一个瓶颈。)

5.1 优化SELECT语句和其它查询

  1. mysql> desc select id from tmp;
  2. <div class="md-section-divider"></div>
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE tmp index NULL PRIMARY 4 NULL 1490 Using index

重点要看的:
type : 联接类型。下面给出各种联接类型,按照从最佳类型到最坏类型进行排序:

type 说明
eq_ref 参与连接运算的表是内表(在代码实现的算法中,两表连接时作为循环中的内循环遍历的对象,这样的表称为内表)。基于索引(连接字段上存在唯一索引或者主键索引且操作符必须是“=”谓词,索引值不能为NULL)做扫描,使得对外表的一条元组,内表只有唯一一条元组与之对应。
ref 对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),操作符只能用=或<=>
ref_or_null 该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。连接字段的值可以为NULL的情况
index_merge 该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。
unique_subquery 在子查询中,基于唯一索引进行扫描,例value IN (SELECT primary_key FROM single_table WHERE some_expr)
index_subquery 在子查询中,基于除唯一索引之外的索引进行扫描
range 范围扫描,基于索引做范围扫描,为诸如BETWEEN,IN,>=,LIKE类操作提供支持。
index 索引做扫描,是基于索引在索引的叶子节点上找满足条件的数据(不需要访问数据文件),即所有须有的数据在索引上就能获得。
ALL 全表扫描

ref:ref列显示使用哪个列或常数与key一起从表中选择行。
rows:显示MySQL认为它执行查询时必须检查的行数。

Extra 说明
using where 使用了where子句来过滤元组
using temporary 用临时表保存中间结果,常用于GROUP BY 和 ORDER BY操作中
using filesort 使用文件完成排序操作,这是可能是ordery by,group by语句的结果,这可能是一个CPU密集型的过程,可以通过选择合适的索引来改进性能,用索引来为查询结果排序。
using index 不需要读取数据文件,从索引树(索引文件)中即可获得信息。如果同时出现using where,表明索引被用来执行索引键值的查找,没有using where,表明索引用来读取数据而非执行查找动作。
Distinct MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。

注意:这里的一个问题是MySQL能更高效地在声明具有相同类型和尺寸的列上使用索引。在本文中,VARCHAR和CHAR是相同的,除非它们声明为不同的长度。因为tt.ActualPC被声明为CHAR(10)并且et.EMPLOYID被声明为CHAR(15),长度不匹配。

5.2 MySQL怎样优化WHERE子句

5.3 INSERT语句的速度

插入一个记录需要的时间由下列因素组成,其中的数字表示大约比例:

连接:(3)
发送查询给服务器:(2)
分析查询:(2)
插入记录:(1x记录大小)
插入索引:(1x索引)
关闭:(1)

这不考虑打开表的初始开销,每个并发运行的查询打开。
表的大小以logN (B树)的速度减慢索引的插入。

加快插入的一些方法:

  1. LOCK TABLES a WRITE;
  2. INSERT INTO a VALUES (1,23),(2,34),(4,33);
  3. INSERT INTO a VALUES (8,26),(6,29);
  4. UNLOCK TABLES;
  5. <div class="md-section-divider"></div>

5.4 DELETE语句的速度

删除一个记录的时间与索引数量确切成正比。为了更快速地删除记录,可以增加键高速缓冲的大小。如果想要删除一个表的所有行,使用TRUNCATE TABLE tbl_name 而不要用DELETE FROM tbl_name。

5.5 其它优化技巧

5.6 锁

对WRITE,MySQL使用的表锁定方法原理如下:

如果在表上没有锁,在它上面放一个写锁。
否则,把锁定请求放在写锁定队列中。

对READ,MySQL使用的锁定方法原理如下:

如果在表上没有写锁定,把一个读锁定放在它上面。
否则,把锁请求放在读锁定队列中。

当一个锁定被释放时,锁定可被写锁定队列中的线程得到,然后是读锁定队列中的线程。
这意味着,如果你在一个表上有许多更新,SELECT语句将等待直到没有更多的更新。
可以通过检查table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定争夺:

mysql> SHOW STATUS LIKE 'Table%';
+-----------------------+---------+
| Variable_name | Value |
+-----------------------+--------+
| Table_locks_immediate | 1151552 |
| Table_locks_waited | 15324 |
+-----------------------+--------+

行级锁定的优点:
+ 当在许多线程中访问不同的行时只存在少量锁定冲突。
+ 回滚时只有少量的更改。
+ 可以长时间锁定单一的行。
行级锁定的缺点:
+ 比页级或表级锁定占用更多的内存。
+ 当在表的大部分中使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁。
+ 如果你在大部分数据上经常进行GROUP BY操作或者必须经常扫描整个表,比其它锁定明显慢很多。
+ 用高级别锁定,通过支持不同的类型锁定,你也可以很容易地调节应用程序,因为其锁成本小于行级锁定。

5.7 MySQL如何使用索引

索引用于快速找出在某个列中有一特定值的行。不使用索引,MySQL必须从第1条记录开始然后读完整个表直到找出相关的行。表越大,花费的时间越多。如果表中查询的列有一个索引,MySQL能快速到达一个位置去搜寻到数据文件的中间,没有必要看所有数据。如果一个表有1000行,这比顺序读取至少快100倍。注意如果你需要访问大部分行,顺序读取要快得多,因为此时我们避免磁盘搜索。

大多数MySQL索引(PRIMARY KEY、UNIQUE、INDEX和FULLTEXT)在B树中存储。只是空间列类型的索引使用R-树。

例如:
mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
如果col1和col2上存在一个多列索引,可以直接取出相应行。如果col1和col2上存在单列索引,优化器试图通过决定哪个索引将找到更少的行来找出更具限制性的索引并且使用该索引取行。
如果表有一个多列索引,优化器可以使用最左面的索引前缀来找出行。例如,如果有一个3列索引(col1,col2,col3),则已经对(col1)、(col1,col2)和(col1,col2,col3)上的搜索进行了索引。

如果列不构成索引最左面的前缀,MySQL不能使用局部索引。假定有下面显示的SELECT语句。

6 语言结构

Tips

使用--safe-updates选项

通常情况,这样的语句从表中删除所有行。用--safe-updates,可以通过指定可以识别它们的键值只删除某些行。
设置方法:
shell>mysql --safe-updates --select_limit=500 --max_join_size=10000
所有大的SELECT结果自动限制到1,000行,除非语句包括一个LIMIT子句。
所有insert最多10000行

SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=1000, SQL_MAX_JOIN_SIZE=1000000

字符串 单引号与双引号的区别

如果SQL服务器模式启用了NSI_QUOTES,可以只用单引号引用字符串。用双引号引用的字符串被解释为一个识别符。

列类型存储

数值类型存储

类型 存储
TINYINT 1个字节
SMALLINT 2个字节
MEDIUMINT 3个字节
INT 4个字节
BIGINT 8个字节
FLOAT(p) 如果0 <= p <= 24为4个字节, 如果25 <= p <= 53为8个字节
FLOAT 4个字节
DOUBLE 8个字节

日期和时间类型的存储

列类型 存储
DATE 3个字节
DATETIME 8个字节
TIMESTAMP 4个字节
TIME 3个字节
YEAR 1个字节

字符串类型的存储

列类型 存储
CHAR(M) M个字节,0 <= M <= 255
VARCHAR(M) L+1个字节,其中L <= M 且0 <= M <= 65535(L详见下面的注释) VARCHAR列的有效最大长度为65,532字符。varchar 字段是将实际内容单独存储在聚簇索引之外,内容开头用1到2个字节表示实际长度(长度超过255时需要2个字节),因此最大长度不能超过在不允许非空字段的时候65533 允许时为65532。如果超过了会被强制转为text
BINARY(M) M个字节,0 <= M <= 255
VARBINARY(M) L+1个字节,其中L <= M 且0 <= M <= 255
TINYBLOB, TINYTEXT L+1个字节,其中L < 2^8
BLOB, TEXT L+2个字节,其中L < 2^16
MEDIUMBLOB, MEDIUMTEXT L+3个字节,其中L < 2^24
LONGBLOB, LONGTEXT L+4个字节,其中L < 2^32
ENUM('value1','value2',...) 1或2个字节,取决于枚举值的个数(最多65,535个值)

注释:VARCHAR、BLOB和TEXT类是变长类型。每个类型的存储需求取决于列值的实际长度(用前面的表中的L表示),而不是该类型的最大可能的大小。例如,VARCHAR(10)列可以容纳最大长度为10的字符串。实际存储需求是字符串(L)的长度,加上一个记录字符串长度的字节。对于字符串'abcd',L是4,

使用INFORMATION_SCHEMA表去查看相关信息

例如:select table_name FROM information_schema.tables ORDER BY table_name DESC;

使用SQL_NO_CACHE禁用缓存查询

select SQL_NO_CACHE count(*) from users where email = 'hello';

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注