读写锁
读锁是共享的,或者说是互不阻塞,多个客户端在同一时刻可以读取同一个资源,写锁是排他的一个写锁会阻塞其他的写锁和读锁.
表锁
表锁是mysql中最基本的锁策略,并且是开销最小的策略.
行级锁
行级锁可以支持最大程度的并发处理,同时也带来了最大的锁开销.
事务
ACID 原子性,一致性,隔离性,持久性
隔离级别
repeatable read(重读)
serializable
-死锁
死锁是指两个或者多个事物在统一资源上相互占用,并请求锁定对方占用的资源,从而导致的恶性循环的现象.当多个事物视图以不同的顺序锁定资源时,就可能会产生死锁的情况.
mysql中提供了两种事务型的存储引擎: InnoDB 和 NDB Cluster
自动提交(autocommit)
mysql默认采用自动提交模式.也就是说,如果不是显式地开始一个事物,则每个查询都被当作一个事物执行提交操作.在当前连接中,可以通过设置autocommit变量来启用或者禁用自动化个提交模式
更小的更好
一般情况下,应该尽量使用可以正确存储数据的最小类型
简单就好
简单的数据类型付出的代价更低
NULL的列使索引,索引统计和值比较都更为复杂
MySql为了兼容性支持很多别名,例如integer,bool,numeric.其实它们都是基本类型
有tinyint,smallint,mediumint,int,bigint.
MySql可以为整数类型指定宽度,但是它不会限制合法范围,对于存储和计算来说,INT(1)和INT(20)是相同的
实数是带有小数部分的数字
例如在财务存储中,数据量较大时,可以考虑使用BIGINT代替DECIMAL,将需要存储的货币单位根据小数的位数乘以相应的倍数即可.假设存储财务数据要精确到万分之一,则可以把所有的金额乘以一百万,然后将结果存储在BIGINT里,同时避免了浮点存储计算不精准和DECIMAL精确计算但是代价高的问题
VARCHAR类型用于存储可变长字符串
CHAR类型是定长的
两者都是为存储很大的数据而设计的字符串类型数据,分别采用二进制和字符方式存储
最好的解决方案是尽量避免使用,如果实在无法避免,有一个技巧实在所有用到BLOB字段的地方都使用SUBSTRING(colum,length)将列值转换为字符串(在 ORDER BY 子句中也适用)
Mysql能存储的最小时间粒度为秒(MariaDB支持微秒级别的时间类型),MySql也同样可以使用微秒来进行临时运算.
DATETIME
这个类型能保存的最大范围值,从1001年到9999年,精度为秒,它把日期和时间封装格式为YYYYMMDDHHMMSS
的整数中,与时区无关,使用8个字节存储空间
TIMESTAMP
它保存了从1970年1月1日午夜以来的秒数.只使用了4个字节
如果想使用更小级别的时间值,可以使用BIGINT来存储时间戳
如果存储UUID赢移除-
符号,用UNHEX()
转换UUID为16字节的数字,并且存储在BINARY(16)
的列中.检索时可以通过HEX()
函数来格式化为十六进制格式
例如IPv4地址,可以使用无符号整数存储,MySql提供INET_ATON()
和INET_NTOA()
函数来转换
太多的列
太多的关联
MySql限制了每个关联操作最多只能有61张表,单个查询最好在12个表以内
可以使用0,某个字符串,或者空字符串作为代替
为了高效载入数据到MyISAM表中,常用技巧是先禁用索引,载入数据,然后重新启用索引
ALTER TABLE test.load_data DISABLE KEYS;
-- load data
ALTER TABLE test.load_data ENABLE KEYS;
该技巧对唯一索引无效
MySql只能高效实用索引的最左前缀列
B-Tree 意味着通常所用的值都是按顺序存储的,并且每一个叶子页到根的距离相同,B-Tree索引能够加快访问数据的速度,因为存储引擎不再需要进行全表扫描来获取需要的数据,取而代之的是从索引的根节点开始搜索.
B-Tree对索引列使顺序组织存储的,所有很适合查找范围数据
B-Tree索引适用于全键值,键值范围或者键前缀查找
全值匹配指的是和索引中的所有的列进行匹配
哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才能有效.
对于每一行数据,存储引擎都会对所有的索引计算一个哈希码,哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样.哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针
在MySql中,只有Memory引擎显式支持哈希索引,这也是Memory引擎表的默认索引类型
=
IN()
,也不支持任何范围查询 例如WHERE price > 100
MyISAM 表支持空间索引,可以用作地理数据存储.和B-Tree索引不同,这类索引无须前缀查询.空间索引会从所有维度来索引数据.查询时,可以有效地使用任意维度来组合查询.
全文索引是一种特殊类型的索引,它查找的是文本中的关键字,而不是直接比较索引中的值.全文搜索和其他几类索引的匹配方式完全不一样.
查询性能低下最基本的原因是访问的数据太多.某些查询可能不可避免地需要筛选大量数据.大部分性能低下的查询都可以通过减少访问的数据量的方式进行优化.对于低效的查询,我们可以通过两个步骤来分析:
有些查询会请求超过实际需要的数据,然后这些多余的数据会被应用程序丢弃.这会给MySql服务器带来额外的负担,并增加网络开销.
MySql的查询状态
Sleep 线程正在等待客户发送新的请求
Query 线程正在执行查询或者正在将结果发送给客户端
Locked 在MySql服务器层,该线程正在等待表锁
Analyzing and statistics 线程正在收集存储引擎统计信息,并且生成查询的执行计划
Copying to tmp table [on disk] 线程正在执行查询,并且将结果集都复制到一个临时表汇总,如果带有on disk
标记,那表示MySql正在讲一个内存临时表放到磁盘上
Sorting result 线程正在对结果集进行排序
Sending Data 线程可能在多个状态之间传送数据,或者正在生成结果集,或者在向客户端发送数据
重新定义关联表的顺序
将外连接转化成内连接
并不是所有的OUTER JOIN语句都必须以外连接的方式执行,例如:WHERE条件,库表结构都可能会让外连接等价于一个内连接
使用等价变换规则
MySql可以使用一些等价变换来简化并规范表达式.它可以合并和减少一些比较,还可以移除一些恒成立和一些恒不成立的判断.例如,(5=5 AND a>5)将被改写而成a>5
索引和列是否为空通常可以帮助MySql优化这类表达式.例如,要找某一列的最小值,只需要查询对应B-Tree索引最左端的记录.类似的,没有任何WHERE条件的COUNT(*) 查询通常也可以使用存储引擎提供的一些优化
当MySql检测到一个表达式可以转化为常数的时候,就会一直把该表达式作为常数进行优化处理
一般建议使用左外连接(LEFT OUTER JOIN)来代替子查询
有时,MySql无法将限制条件从外层下推到内层,这使得原本能够限制部分返回结果的条件无法应用到内层查询优化上.
如果希望UNION的各个子句能够根据LIMIT只取部分结果集,或者希望能够先排好序再合并结果集的话,就需要在UNION的各个子句中分别使用这些子句.
select count(*) from test where id > 5
我们可以这样优化
select (select count(*) from test) - count(*) from test where id <=5
这其中的子查询会被当做一个常数来处理
优化此类分页查询的一个最简单的办法就是尽可能地使用索引覆盖扫描.
select id from test order by name limit 50,5;
可以有以下几种方式
select id from test where position between 50 and 54 order by position;
select * from test where id < 999 order by id desc limit 20;