HASH(id DIV 1000000)
,这将为100万数据创建一个分区。一方面实现了当初分区的目的,另外一方面比起使用时间范围分区还避免了一个问题,就是当超过必定阈值时,若是使用时间范围分区就必须新增分区。上一节介绍的两个分区策略都基于两个很重要的假设:查询可以过滤掉不少额外的分区,分区自己并不会带来不少额外的代价。node
可能会遇到问题的场景:mysql
NULL值会使分区过滤无效算法
分区的表达式的值能够是NULL:第一个分区是一个特殊分区。sql
PARTITION BY RANGE YEAR(order_date)
分区,那么全部order_date为NULL或者是一个很是值的时候,记录都会放到第一个分区。
WHERE order_date BETWEEN '2012-01-01' AND '2012-01-31'
,实际上MySQL会检查两个分区,由于YEAR()在接收非法值时会返回NULL而把记录放到第一个分区。PARTITION p_nulls VALUES LESS THAN (0)
。这样即便须要检查第一个分区,代价也很是小PARTITION BY RANGE COLUMNS(order_date)
分区实现中的一些其余限制:数据库
访问分区表,需在WHERE条件中带入分区列,即便有时候看似多余,这样就可让优化器过滤掉无须访问的分区。编程
MySQL只能在使用分区函数的列的自己进行比较才能过滤分区,而不能根据表达式的值去过滤分区,即便这个表达式就是分区函数也不行。这和查询中使用独立的列才能使用索引的道理是同样的。缓存
-- 没法使用分区
mysql> EXPLAIN PARTITIONS SELECT * FROM sales_by_day WHERE YEAR(day) = 2010\G;
-- 可以使用分区
mysql> EXPLAIN PARTITIONS SELECT * FROM sales_by_day
-> WHERE day BETWEEN '2010-01-01' AND '2010-12-31'\G;复制代码
优化器在处理查询的过程当中老是尽量聪明地去过滤分区。例如,若分区表是关联操做中的第二张表,且关联条件是分区键,MySQL就只会在对应的分区里匹配行。(EXPLAIN没法显示这种状况下的分区过滤,由于这是运行时的分区过滤,而不是查询优化阶段的)安全
合并表是一种早期的、简单的分区实现,和分区表相比有一些不一样的限制,而且缺少优化。合并表容许用户单独访问各个子表。分区表是将来的发展趋势,合并表是一种将被淘汰的技术,在将来版本可能会被删除,在这里不作过多阐述。服务器
视图自己是一个虚拟表,不存听任何数据。在使用SQL语句访问视图的时候,它返回的数据是MySQL从其余表生成的。网络
工做原理:
-- 实现视图最简单的办法是将SELECT语句的结果存放到临时表中。
mysql> CREATE VIEW Oceania AS
-> SELECT * FROM Country WHERE Continent = 'Oceania'
-> WITH CHECK OPTION;
-- 当须要访问视图的时候,可直接访问这个临时表
mysql> SELECT Code, Name FROM Oceania WHERE Name = 'Australia';
-- MySQL使用的并算法:重写含有视图的查询,将视图的定义SQL直接包含进查询的SQL中:
mysql> SELECT Code, Name FROM Country
-> WHERE Continent = 'Oceania' AND Name = 'Australia';
-- MySQL 使用的临时表算法,如下SQL是为展现用的。这样作会有明显的性能问题,优化器也很难优化在这个临时表上的查询。
mysql> CREATE TEMPORARY TABLE TMP_Oceania_123 AS
-> SELECT * FROM Country WHERE Continent = 'Oceania';
mysql> SELECT Code, Name FROM TMP_Oceania_123 WHERE Name = 'Australia';复制代码
MySQL使用合并算法 和临时表算法 来处理视图。若是可能,尽量使用合并算法。
两种算法的实现细节:
使用临时表算法实现视图的场景:
视图的实现算法是视图自己的属性,和做用在视图上的查询语句无关。例如,能够为一个基于简单查询的视图制定使用临时表算法:CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM sakila.actor;
,这样不管基于执行什么样的查询,视图都会生成一个临时表。
CHECK OPTION
子句表示任何经过视图更新的行,都必须符合视图自己的WHERE条件定义。因此不能更新视图之外的列MySQL还不支持物化视图(指视图结果数据存放在一个能够查看的表中,并按期从原始表刷新数据到这个表),也不支持在视图中建立索引。可使用构建缓存表或者汇总表的办法来模拟物化视图和索引
MySQL并不会保存视图定义的原始SQL语句,因此不能经过执行SHOW CREATE VIEW后再简单地修改其结果的方式来从新定义视图。
若是打算修改视图,而且无法找到视图的原始的建立语句的话,能够经过使用视图.frm文件最后一行获取一些信息。若是有FILE权限,甚至可直接使用LOAD_FILE()来读取.frm中的视图建立信息,在加上一些字符处理工做。
mysql> SELECT
-> REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
-> REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
-> SUBSTRING_INDEX(LOAD_FILE('/var/lib/mysql/world/Oceania.frm'),
-> '\nsource=', −1),
-> '\\_','\_'), '\\%','\%'), '\\\\','\\'), '\\Z','\Z'), '\\t','\t'),
-> '\\r','\r'), '\\n','\n'), '\\b','\b'), '\\\"','\"'), '\\\'','\''),
-> '\\0','\0')
-> AS source;复制代码
在将来一段时间还不会用到,须要用到再看,感受更适合DBA,这里只列举经常使用的方式。
能够在执行INSERT、UPDATE或者DELETE的时候,执行一些特定的操做。能够在MySQL中指定是在SQL语句执行前触发仍是在执行后触发。
相似于LINUX的定时任务,不过彻底是在MySQL内部实现。
MySQL在服务器中提供只读的、单向的游标,并且只能在存储过程或者更底层的客户端API中使用。由于游标中指向的对象都是存储在临时表中而不是实际查询到的数据,因此MySQL游标老是可读的。
INSERT INTO tbl(col1, col2, col3) VALUES (?, ?, ?);
。绑定变量的SQL,使用问号标记能够接收参数的位置,当真正须要执行具体查询的时候,则使用具体值代替这些问号。理论上有些优化器只须要作一次,但实际上,下面的操做仍是都会被执行。根据优化器何时工做,能够将优化分为三类:
最主要的用途就是在存储过程当中使用。
三种绑定变量类型的部分区别:
使用支持C语言调用约定的任何编程语言来实现用户自定义函数(UDF)。UDF必须事先编译后并动态连接到服务器上。
插件类型:
字符集是指一种从二进制编码到某类字符符号的映射,能够参考如何使用一个字节来表示英文字符。校对是指一组用于某个字符集的排序规则。
每种字符集均可能有多种校对规则,而且都有一个默认的校对规则,每一个校对规则都是针对某个特定的字符集,所以把字符集和校对规则统称为字符集。
MySQL有不少选择用于控制字符集,这些选项和字符集很容易混淆。只有基于字符的值才真正的有字符集的概念。对于其余类型的值,字符集只是一个设置,指定用哪一种字符集来作比较或者其余操做。
MySQL的设置:
建立对象时的默认设置:
服务器和客户端通讯时的设置:
服务器和客户端通讯的时候,他们可能使用不一样的字符集。这时,服务器端将进行必要的翻译转换工做:
根据须要,可使用SET NAMES或者SET CHARACTER语句来改变上面的设置。不过在服务器上使用这个命令只能改变服务器端的设置。客户端程序和客户端的API也须要使用正确的字符集才能避免在通讯时出现问题。
MySQL比较两个字符串的大小时,经过将其转换成同一个字符集再进行比较,若是两个字符集不兼容的话,则会抛出错误。MySQL还会为每一个字符串设置一个“可转换性”,这个设置决定了值的字符集的优先级,于是会印象MySQL作字符集隐式转换后的值。
还可使用前缀和COLLATE子句来指定字符串的字符集或者校对字符集。
mysql> SELECT _utf8 'hello world' COLLATE utf8_bin;复制代码
一些特殊状况:
可使用命令SHOW CHARACTERSET和SHOW COLLATION来查看MYSQL支持的字符集和校对规则。
极简原则:最好先为服务器或者数据库选择一个合理的字符集,而后根据不一样的实际状况,让某些列选择合适的字符集。
对于校对规则一般须要考虑的一个问题是,是否以大小写敏感的方式比较字符串,或者是以字符串编码的二进制值来比较大小。二进制校对规则直接使用字符的字节进行比较,而大小写敏感的校对规则在多字节字符集时如德语有更复杂的比较规则。
MySQL如何选择字符集和校对规则:
某些字符集和校对规则可能会须要更多的CPU操做、消耗更多的内存和存储空间,甚至还会影响索引的正常使用。
计算每个文档对象和查询的相关度。相关度是基于匹配的关键词个数,以及关键词在文档中出现的个数。在整个索引中出现次数越少的词语,匹配的相关度就越高,相反很是常见的单词就不会被搜索。
能够在查询中自定以某个被搜索词语的相关性。布尔搜索经过停用词列表过滤掉那些噪声词,另外还要求搜索的关键词长度必须大于ft_min_word_len并小于ft_max_word_len。搜索返回的结果是未经排序的。
存储引擎的事务特性能勾保证在存储引擎级别实现ACID,而分布式事务则让存储引擎级别的ACID扩展到数据库层面,甚至扩展到多个数据库之间,这须要两个阶段提交实现:
MySQL的缓存类型:
MySQL查询缓存保存查询返回的完整结果。当查询命中该缓存,MySQL会马上返回结果,跳过了解析、优化和执行阶段。
随着如今的通用服务器愈来愈大,查询缓存被发现是一个影响服务器扩展性的因素。它可能成为整个服务器的资源竞争单点,在多核服务器上还可能致使服务器僵死。建议默认关闭查询缓存,若是查询缓存做用很大的话,那就配置一个很小的查询缓存空间(如几十兆)。
缓存存放在一个引用表中,经过一个哈希值引用,这个哈希值包括了以下因素:即查询自己、当前要查询的数据库、客户端协议的版本等一些其余可能会影响返回结果的信息。
当判断缓存是否命中时,MySQL不会解析、“正规化”或者参数化查询语句,而是直接使用SQL语句和客户端发送过来的其余原始信息。任何字符上的不一样,例如空格、注释,都会致使缓存不命中。
当查询语句中有一些不肯定的数据时,则不会被缓存。例如包含函数NOW()或者CURRENT_DATE的查询都不会被缓存。
-- 若是但愿换成一个带日期的查询,那么最好将其日期提早计算好,而不要直接使用函数
... DATE_SUB(CURRENT_DATE, INTERVAL 1 DAY) -- Not cacheable!
... DATE_SUB('2007-07-14’, INTERVAL 1 DAY) -- Cacheable复制代码
子查询和存储过程都没办法使用查询缓存,另外5.1版本以前,绑定变量也没法使用。由于查询缓存是在完整的SELECT语句基础上的,并且只是在刚收到SQL语句的时候才检查。
查询缓存在不少时候能够提高查询性能,但自己是一个加锁排他操做,另外打开查询缓存对读和写都会带来额外的消耗:
对InnoDB来讲,事务的一些特性会限制查询缓存的做用。当一个语句在事务中修改了某个表,MySQL会将这个表的对应的查询缓存都设置失效,而事实上,InnoDB的多版本特性会暂时将这个修改对其它事务屏蔽。
若是查询缓存使用了很大量的内存,缓存失效操做就可能会成为一个很是严重的问题瓶颈。
查询缓存是彻底存储在内存中。
理想流程:
实际流程:
假设平均查询结果很是小,服务器在并发地向不一样的两个链接返回结果,返回完结果后MySQL回收剩余数据块空间时会发现,回收的数据块小于query_cache_min_res_unit,因此不可以直接在后续的内存块分配中使用。考虑到这种状况,数据块的分配就更复杂些。
Qcache_lowmem_prunes
来查看有多少次失效是因为内存不足致使的。配置:
减小碎片
提升查询缓存的使用率
查询缓存的工做原则是:执行查询最快的方式就是不去执行。可是查询仍然要发送到服务器端,服务器端还须要作一点点工做。所以能够直接在客户端进行缓存。