More Related Content Similar to 对MySQL应用的一些总结 (20) 对MySQL应用的一些总结2. Topics of Discussion(上午)
l MySQL缺陷与适用场景
l MyISAM vs InnoDB
l MyISAM与InnoDB性能调优
l MySQL Server性能调优
l MySQL Join算法
l MySQL 优化器特性
l 索引设计杂谈
6. MySQL缺陷
Ø MySQL没有Hash Join à 不适合无索引大数据
量数据分析
Ø MySQL没有完整的CBO à 不可依赖MySQL选
择最优的执行计 ,不可依赖MySQL自行优化
SQL
Ø MySQL没有备块级 制 à 不可依赖MySQL保证
备库的实时一致性
Ø MySQL无法有效利用主机资源 à 单机单实例会
严重的浪费机器性能
7. MySQL适用场景
ü 应用会产生庞大连接数(Thread)
ü 可以依赖索引完成的数据分析(Covering
Index)
ü 高并发查询(MyISAM)
ü 短小的在线事务处理(InnoDB)
ü 简单条件查询(HandlerSocket)
ü 数据拆分(Free)
9. MyISAM的优势和劣势
优势 劣势
小内存下更快速的查询:
数据文件容易损坏:
因为没有复杂的MVCC多版本控 因为数据回写机制没有原子性
制机制 保证
更小的数据文件:
没有事务保证
因为数据文件中没有额外的行
锁和事务信息
非常容易冷备份:
只有索引缓存
因为每张表三个文件,没有额
外的全局信息,拷贝文件即可
备份
表级锁,并发差
10. InnoDB的优势和劣势
优势 劣势
行级锁,并发高:
小内存下纯读应用不如MyISAM
只锁定被访问到的行,并不影 快
响对不同行的操作。
ACID事务保证 备份操作更复杂:
因为存在事务信息,多版本信
息,不能简单的拷贝数据文件。
但是支持热备份。
所有数据文件均可缓存:
更占用磁盘空间:
InnoDB主键索引即数据,缓存 因为行结构中包含事务信息和
索引就包括了缓存数据 行锁信息,另外有UNDO和REDO
事务日志
读写互不阻塞:
得益于MVCC多版本控制,读数
据并不需要锁定修改,可以在
UNDO日志中找到旧版本。
11. 索引对比
MyISAM InnoDB
B-‐Tree结构,不能自动Balance B+Tree结构,自动Balance
堆表:
索引组织表:
数据文件独立于索引,数据文 数据文件以主键顺序组织,主
件以插入顺序组织,以物理位 键即数据,非主键索引通过主
置为引用键,索引通过物理位 键查找数据行。所以主键插入
置查找数据行。 无序时性能极差。
支持自适应哈希:
当InnoDB发现表上经常存在某
些唯一键上的KV查询时,会自
动把这部分数据生成到自适应
哈希表中,可进行KV查询优化。
主键索引包含事务信息:
主键索引上唯一确定了一行数
据,所以事务信息包含在主键
索引上。如果没有显示定义主
键索引,将自动建立隐含主键。
12. MyISAM场景
ü 数据仓库:大量读,批量写,可共享数据文件
ü 日志系统:只有插入没有修改,简单查询
ü 读为主的应用:没有写或写 少,几乎不阻塞读
ü 低并发的应用:表锁基本不影响并发
ü 大数据批量导入:避免InnoDB索引组织表主键
乱序时插入慢
13. InnoDB场景
ü 高并发的应用:例如消息队列
ü 可靠性要求高的应用:例如用户登陆信息
ü 数据一致性要求高,宕机可 :例如用户数据
ü 要求事务和约束的应用:例如有数据 联的系统
ü 需要高性能缓冲写的应用:例如短时间内大量
UPDATE
14. 同时使用MyISAM / InnoDB
Ø 不可共享缓存空间
Ø SQL包含 表将失去事务意义
总之不推荐这 表同时存在同一实例,除非:
表没有 联,MyISAM表只做备份冗余。
但是,Master用InnoDB,Slave用MyISAM某些情
况下是不错的方案。
16. MyISAM优化
l INSERT 优化
l Key Buffer 优化
17. MyISAM 插入
Ø 定⻓长表优于变⻓长表,即尽可能不定义变⻓长字段
Ø 数据存储按插入顺序,除非删除了数据产生的空
洞可以插入新行 或 使用了并发插入
Ø 可以加大bulk_insert_buffer_size变量,采用
”INSERT INTO table VALUES (),(),...” 的批量插
入语法,或者采用LOAD DATA语法
20. Key Buffer 介绍
作用:缓存MyISAM的索引,默认16M
相 变量:key_buffer_size(Key Buffer大小)
相 状态量:
n key_read/write_requests(索引逻辑读/写)
n key_reads/writes(索引物理读/写,即磁盘读/写)
n key_blocks_used/unused(已使用/未使用的缓冲块)
n key_blocks_not_flushed(未回写的脏缓冲块)
21. Key Buffer 监控
Ø 命中率 = (requests - reads) / requests
Ø 利用率 = key_blocks_used / (key_blocks_used +
key_blocks_unused)
Ø 赃⻚页率 = key_blocks_not_flushed /
(key_blocks_used + key_blocks_unused)
23. 多段 Key Buffer
少Key Buffer锁的竞争:
将Key Buffer拆分为多个段,分 缓冲不同的表。
! root@localhost : (none) 04:16:36> SET GLOBAL hot_cache.key_buffer_size=128*1024;
! Query OK, 0 rows affected (0.00 sec)
! root@localhost : mysql 04:28:05> CACHE INDEX user IN hot_cache;
! +------------+--------------------+----------+----------+
! | Table | Op | Msg_type | Msg_text |
! +------------+--------------------+----------+----------+
! | mysql.user | assign_to_keycache | status | OK |
! +------------+--------------------+----------+----------+
! 1 row in set (0.00 sec)
24. 预载入 Key Buffer
少Key Buffer预热时间:
预先载入指定表的索引到指定缓冲段。
! root@localhost : mysql 04:28:13> LOAD INDEX INTO CACHE user;
! +------------+--------------+----------+----------+
! | Table | Op | Msg_type | Msg_text |
! +------------+--------------+----------+----------+
! | mysql.user | preload_keys | status | OK |
! +------------+--------------+----------+----------+
! 1 row in set (0.00 sec)
25. Key Buffer 建议
最好可以保证Key Buffer Size大于目前所有需要访
问的表MYI文件大小总和。
如无法保证则一般分三个区给不同业务类型的表:
n 静态缓冲区, 少或不修改的表,这个区的Key Buffer访问没有
写锁,都是Shared Read Lock。
n 修改缓冲区,大量修改或UPDATE的表,这个区的Key Buffer竞
争严重,限制竞争在一个区。
n 普通缓冲区,除大量修改和只读表以外的正常读写比例的表。
28. InnoDB 简介
Ø InnoDB是MySQL上应用最广的事务引擎,淘宝
商品库、阿里巴巴商品信息全部 在InnoDB
上。
Ø InnoDB目前包含 个版本,InnoBase和InnoDB
Plugin,5.1之前只有InnoBase,5.1之后 始有
InnoDB Plugin。另外还有基于MySQL Server和
InnoDB Plugin优化的Percona Server和
XtraDB。
Ø 前阿里巴巴正在使用的就是Percona+XtraDB高
性能版本,完全兼容MySQL。
30. InnoDB 数据文件组织
Ø 最基本的修改单位是Row
Ø 最基本的IO单位是Page,包含2个以上Row
Ø 最基本的分配单位是Extent,包含64个Page
Ø InnoDB的索引都是指到Page no为止,为了B-
Tree保持高效,InnoDB要求一个Page内至少有
2行数据,所以我们建议每行数据设计⻓长度不要
超过4K,这样我们可以方便的 移到最平衡的
8K⻚页大小。
35. Buffer Pool 设置
innodb_buffer_pool_size设置Buffer Pool的大小。
建议将除了连接使用的内存,操作系统使用的内存
之外的全部内存给Buffer Pool,不要靠操作系统的
OS Cache来缓冲缓存数据。
经验参考值:
n 48G内存:32G Buffer Pool
n 32G内存:20G Buffer Pool
n 24G内存:16G Buffer Pool
n 16G内存:10G Buffer Pool
36. Buffer Pool 赃⻚页比例
Buffer Pool同时担任缓冲和缓存工作,因此Buffer
Pool中会产生赃⻚页,即在内存中修改了但未刷新到
磁盘上的⻚页。
innodb_max_dirty_pages_pct变量可以配置最多允
许多少比例的赃⻚页在内存中,超过比例将触发刷
新。
经验参考值:
n 75%适用于绝大部分情况,Google/Facebook/Alibaba均使用
n 5%适用于非常在意宕机快速 的情况,Taobao/Alipay使用
37. InnoDB 事务安全
Ø REDO LOG:所有变更内容全部写入REDO LOG。一
旦数据库Crash,将redo中已经标记为commit状态的事
务全部重做到数据文件,将没有标记为commit的事务在
数据文件中回 。
Ø UNDO LOG:所有数据被修改的旧版本数据和版本号
写入undo,当需要回 事务时,在undo中找到旧版本
信息,覆盖数据文件。
Ø Double Write Buffer:所有的⻚页级回写,都先将⻚页写
入Double Write Buffer区域, 认CheckSum与内存中
的⻚页一致,再正式写入数据文件中,如果数据库Crash,
数据文件中的⻚页没有回写完成,可以从Double Write
Buffer中读取正 的⻚页重写。
39. Log Buffer
Ø 事务安全使得InnoDB会产生事务日志,包括
REDO和UNDO。日志回写到磁盘会有一个Log
Buffer缓冲日志写
Ø innodb_log_buffer_size设置事务日志缓冲大小
Ø 经验参考值:
n 默认只有1M,存在大事务或者高并发情况,建议设置8~16M
40. InnoDB 事务提交
Ø Log Buffer中缓冲的日志在检查点或事务提交时
回写文件。
Ø Buffer Pool中的⻚页在检查点时回写磁盘。
Ø innodb_flush_log_at_trx_commit控制回写:
n 0: 每秒刷新日志到文件(不是磁盘)
n 1: 每次事务提交刷新日志到磁盘 [default]
n 2: 每次事务提交刷新日志到文件,每秒同步到磁盘 [建议]
41. 日志大小设置
Ø 更大的事务日志意味着什么?
n 可以记录更大的事务信息 [可以重做更大的事务]
n 可以记录更⻓长的事务历史 [可以重做更多的事务]
n 更少的检查点 [ 少磁盘IO]
n 更⻓长的 时间 [宕机重启时间更⻓长]
Ø 经验参考值:
n 64M的日志5分钟以内就可以
n 1G的日志全部重做需要30分钟以上
n 我们设置为3个1G的日志
42. InnoDB 锁机制
Ø InnoDB锁算法:写数据有索引时采用间 锁(Gap
Lock),无索引时采取表锁。读利用MVCC机制,不加
锁。所以DELETE / UPDATE的条件没有加索引后果很
严重。
n WHERE pk = 1,锁定pk=1的行,不可以修改pk=1的数据。
n WHERE pk > 1,锁定pk>1后的所有行,不可以操作pk>1的
数据,包括插入删除修改。
n WHERE pk BETWEEN 1 AND 10,锁定1~10内所有行,不
可以操作pk在1~10的所有数据。
Ø InnoDB锁结构:通过为每个⻚页生成一个锁定位图,判
定行是否被锁定,每⻚页的第一行和最后一行是系统行,
如果被锁定说明整⻚页被锁。
43. InnoDB MVCC
Ø 多版本实现:
! 数据旧版本写入UNDO LOG,数据Page中保留最新数据和版本
号,当Query发现Page中的数据版本太新,则顺着undo log
pointor到UNDO LOG寻找到需要的历史版本,所以读取数据不
需要加锁。
Ø 事务可⻅见性判定:
! MVCC需要做版本可⻅见性判定,以 认一个版本号的数据是否可
以为当前事务所⻅见。InnoDB使用read view结构来实现版本可⻅见,
一个事务起始时,会被分配一个read view,包含当前正在执行的
事务号,根据不同的隔离级 需求,可以依据read view的事物号
信息来判定行数据可⻅见性。
! 例如MySQL默认隔离级 为可重 读(Repeatable Read),那
么只要读取到的数据事务号大于read view中的最小事务号,就是
不可⻅见的。
44. 自适应哈希
Ø 自适应哈希是InnoDB的天才设计之一,InnoDB存储引
擎会智能的监控对表上索引的查找,如果观察到建立哈
希索引可以带来速度的提升,则自动建立哈希索引。
Ø 自适应哈希索引通过缓冲池的B+树构造而来,因此建立
的速度很快。并不将整个表都建哈希索引,InnoDB存
储引擎会自动根据访问的频率和模式来为某些⻚页建立哈
希索引。
! -------------------------------------
! INSERT BUFFER AND ADAPTIVE HASH INDEX
! -------------------------------------
! Ibuf: size 2249, free list len 3346, seg size 5596,
! 374650 inserts, 51897 merged recs, 14300 merges
! Hash table size 4980499, node heap has 1246 buffer(s)
! 1640.60 hash searches/s, 3709.46 non-hash searches/s
45. Insert Buffering
Ø Insert Buffer是InnoDB的另一个天才设计,当有数据更
新时,不立刻更新Index叶子节点的Page,而是将这些
更新缓冲起来,因此对同一个Page的更新可以一起回
写,这 将离散IO整合为顺序IO的设计,非常适合现在
的SSD盘。
Ø 但是Insert Buffer只对非唯一索引起作用,因为在做
Merge之前检查值是否唯一是不可能的。
! -------------------------------------
! INSERT BUFFER AND ADAPTIVE HASH INDEX
! -------------------------------------
! Ibuf: size 7545, free list len 3790, seg size 11336,
! 8075308 inserts, 7540969 merged recs, 2246304 merges
46. InnoDB 优化实践
ü 尽可能使用小的主键: 少非主键索引大小
ü 按主键顺序插入数据:避免主键节点分裂
ü 加大日志大小:避免过多的检查点
ü 避免大事务回 :会产生大量的随机IO,拆分事
务
ü 避免零散的插入:尽可能批量插入
ü 尽量 用前缀索引:InnoDB不会压缩索引
47. InnoDB 其他重要变量
Ø innodb_additional_mem_pool_size:内部元信
息缓存,16M足以胜任任何情况
Ø innodb_support_xa:是否支持 段提交协议,
没有必要 启, 闭可获得10%的性能提升。
48. InnoDB Plugin 增强
Ø IO容量:innodb_io_capacity
Ø IO线程数:
n innodb_read_io_threads(预读)
n innodb_write_io_threads(赃⻚页回写)
n innodb_use_purge_thread(清理UNDO)
Ø 可变⻚页大小(innodb_page_size)
Ø 可配置多回 段(innodb_extra_rsegments)
Ø Compressed表结构:CPU换IO,压缩空间
Ø 扩展INFORMATION_SCHEMA
49. InnoDB Plugin 配置
Ø 建议经验值:
n innodb_io_capacity = 磁盘数*200 (SSD>4000)
n innodb_read_io_threads = 4
n innodb_write_io_threads = CPU核数/实例数*2
n innodb_use_purge_thread = 回 段/2
n innodb_page_size = 8K (全表扫描16K,小数据4K)
n innodb_extra_rsegments = 平均并发插入数,但不要超过
CPU数*2
n 字符型列为主的表设置Compressed表结构
51. Table Cache 介绍
Table Cache是表高速缓存,缓存表文件句柄,每
张表被访问前线程都需要获得它的文件句柄,如果
在表缓存中命中,则不需要再次打 文件,直接从
缓存中获取文件句柄。
! root@localhost : (none) 12:36:11> show global status like 'open%tabl%';
! +--------------------------+-------+
! | Variable_name | Value |
! +--------------------------+-------+
! | Open_table_definitions | 18 |
! | Open_tables | 12 | # 当前打 的表数量
! | Opened_table_definitions | 24 |
! | Opened_tables | 24 | # 表曾经被打 多少次
! +--------------------------+-------+
52. Table Cache 调优
建议经验值:
n 一般table_open_cache=1024适用于大部分情况。
n 如果opened_tables不断增⻓长,应调大table_open_cache。
查看目前打 的表:
! root@localhost : (none) 12:39:24> show open tables;
! +----------+--------------+--------+-------------+
! | Database | Table | In_use | Name_locked |
! +----------+--------------+--------+-------------+
! | mysql | servers | 0 | 0 |
! | mysql | event | 0 | 0 |
! | test | t3 | 0 | 0 |
! | mysql | procs_priv | 0 | 0 |
! | mysql | db | 0 | 0 |
! | mysql | host | 0 | 0 |
! | test | t2 | 0 | 0 |
! +----------+--------------+--------+-------------+
53. Query Cache 介绍
Query Cache是独立于存储引擎的SQL级缓存,它
实际上是SQL文本的MD5值和SQL执行结果的哈希
键对。因此Query Cache的使用受到很大限制:
n SQL文本必须完全相同,包括大小写,空格
n 存在不 定函数的SQL不被缓存,例如NOW()
n PREPARE方式执行的SQL不被缓存
n 自定义函数,存储过程,视图均不能被缓存
54. Query Cache 设置
Ø 配置参数:
n query_cache_type:
n OFF:不对SELECT结果集缓存
n ON:对SELECT结果集缓存 [默认]
n DEMAND:只有当SELECT语句中显示写明“SQL_CACHE”时候才对
结果集缓存 [推荐]
n query_cache_size:Query Cache大小
n query_cache_limit:可缓存的最大结果集,默认1MB
n query_cache_min_res_unit:内存分配最小单位,默认4KB
Ø 经验参考值:
n InnoDB应该 闭QCache,因为InnoDB有MVCC
n MyISAM如果 实数据很少变化,可以测试常用SQL的结果集
大小,设置为最常用的SQL的结果集
55. Query Cache 监控
Ø 命中率 = Qcache_hits / (Com_select + Qcache_hits)
Ø 利用率 = (query_cache_size -
Qcache_free_memory) / query_cache_size
Ø 碎片率 = Qcache_free_blocks / Qcache_total_blocks
! mysql> show status like ‘Qcache%’;
! +-------------------------+----------+
! | Variable_name | Value |
! +-------------------------+----------+
! | Qcache_free_blocks | 1 | # 缓存中有多少未被使用空闲的内存块
! | Qcache_free_memory | 16768400 | # 可用的缓存空间
! | Qcache_hits | 0 | # 缓存命中的次数
! | Qcache_inserts | 0 | # 被缓存的查询次数,也就是没有命中的次数
! | Qcache_lowmem_prunes | 0 | # 由于内存不足导致被删除的缓存条目数量
! | Qcache_not_cached | 64 | # 无法被缓存的查询的数量
! | Qcache_queries_in_cache | 0 | # 当前被cache的查询数量
! | Qcache_total_blocks | 1 | # 当前使用的内存块的数量
! +-------------------------+----------+
56. Query Cache 优化
Ø 如果Qcache_lowmem_prunes很大,说明Query
Cache大小不足
Ø 如果命中率很低,说明Query Cache没有必要
Ø 如果Qcache_free_blocks很大,说明Query
Cache需要整理碎片,Flush Query Cache。
Ø query_cache_min_res_unit =
(query_cache_size - Qcache_free_memory) /
Qcache_queries_in_cache
57. Thread Cache 介绍
每个连接到MySQL都需要创建一个线程,Thread
Cache就缓存了已经断 的连接线程描述符,如果
创建线程前检测到Thread Cache还有可用线程,
就不需要新创建,从缓存中获取即可。
! void create_thread_to_handle_connection(THD *thd) {
! if (cached_thread_count > wake_thread) { //看线程缓存(thread_cache)中有否空
余的线程
! thread_cache.append(thd);
! pthread_cond_signal(&COND_thread_cache); // 有的话则唤醒一个线程来用
! } else {
! threads.append(thd);
! pthread_create(&thd->real_id,&connection_attrib,
handle_one_connection, (void*) thd))); //没有可用空闲线程则创建一个新的线程
! }
! }
58. Thread Cache 配置
Ø 经验建议值:
n thread_cache_size = 1024 适应绝大部分场景
n 并发连接数很少时,相应降低配置
Ø 优化建议:
n 如果threads_created增⻓长很快,应该调大thread_cache_size
的值
59. 连接数
Ø 配置变量:
n max_connections限制全局连接数
n max_user_connections限制每个用户的连接数
Ø 建议经验值:
n max_user_connections:没有特殊情况不用限制
n max_connections:默认100。一般1000个连接可以满足绝大
部分应用,但是应注意,每个连接都会申请线程级内存(包
括Sort Buffer,Join Buffer,Binlog Cache等),要考虑内存
是否可以承受。
n 我们设置为3000,因为很少有连接需要排序和JOIN,一般不
需要多少线程级内存。
60. Sort Buffer 介绍
Ø 每个线程需要排序的时候都会申请一块Sort
Buffer,线程第一次使用的时候分配,连接断
后线程不销毁则内存不释放。
Ø 如果要排序的数据大于Sort Buffer将会用归并排
序法分块排序,超出内存部分写入磁盘暂存。
Ø sort_buffer_size 根据需要排序的数据集大小而
定,可以按照Session在连接内重新设定。
61. Sort Buffer 监控
Ø Sort_merge_passes:归并排序次数,这个值很大说明
Sort Buffer不 ,很多排序数据写到磁盘上了
Ø Sort_rows:被排序数据的行数
Ø Sort_range:通过索引选择了一个范围的数据后排序
Ø Sort_scan:通过全表扫描进行排序的次数,这个值很
大应该优化索引避免排序
62. Join / Read Buffer
Ø join_buffer_size:JOIN时如果不能用到索引就
会使用Join Buffer进行JOIN,最好优化索引避免
使用Join Buffer。
Ø read_buffer_size:全表扫描时缓存读取的数
据,最好通过索引避免全表扫描。
63. Tmp Table 介绍
当执行计 中有Using temporary时表示要采用临时
表完成SQL。
tmp_table_size配置在内存中分配临时表的最大限
制,超过部分将建到磁盘上。
! root@localhost : test 04:21:53> explain select * from t1,t2 where t1.info=t2.info
order by t1.id;
! +----+-------------+-------+------+---------------+------+---------+--------------
+------+---------------------------------+
! | id | select_type | table | type | possible_keys | key | key_len | ref |
rows | Extra |
! +----+-------------+-------+------+---------------+------+---------+--------------
+------+---------------------------------+
! | 1 | SIMPLE | t2 | ALL | NULL | NULL | NULL | NULL |
2 | Using temporary; Using filesort |
! | 1 | SIMPLE | t1 | ref | idx | idx | 32 | test.t2.info |
1 | Using index |
! +----+-------------+-------+------+---------------+------+---------+--------------
+------+---------------------------------+
64. Tmp Table 监控
Ø 重要状态:
n Created_tmp_disk_tables: 件磁盘临时表数量
n Created_tmp_tables:创建临时表数据
Ø 建议经验值:
n 一般tmp_table_size设置为64M足以应对大部分情况
n 如果Created_tmp_tables增⻓长很快,最好优化SQL和索引避
免临时表
n 如果Created_tmp_disk_tables增⻓长很快,应调大
tmp_table_size的值
66. JOIN 算法概述
Ø MySQL只有一 JOIN算法:Nested Loop Join
Ø Nested Loop Join:选择一张驱动表,用 联字
段循环匹配被驱动表
! FOR EACH ROW row1 IN table1 {
! FOR EACH ROW row2 IN table2 IF( 联条件) {
! result := row1 || row2;
! OUTPUT result;
! } }
Ø 支持条件下推(Push Down):先用条件过滤驱动
表和被驱动表,再把过滤后的结果集进行JOIN
67. 内连接
Ø 假定我们有一个如下形式的表T1、T2、T3的联
接查询:SELECT * FROM t1 INNER JOIN t2 ON c1(t1,t2) INNER JOIN
t3 ON c2 (t2,t3) WHERE c(t1,t2,t3)
Ø MySQL首先由优化器判定JOIN顺序,假设生成
执行计 为t1驱动t2驱动t3:
! FOR EACH ROW row1IN t1 IF (c(t1)){
! FOR EACH ROW row2 IN t2 IF (c1(t1,t2) && c(t2)) {
! FOR EACH ROW row3 IN t3 IF (c2(t2,t3) && c(t3)) {
! result := row1 || row2 || row3;
! OUTPUT result;
! } } }
Ø 将行传给下一层被驱动表匹配时,先用条件进行
过滤, 少参与JOIN的行数
68. 外连接
Ø SQL同前例:
! FOR EACH ROW row1 IN t1 IF c1(t1) {
! BOOL f1 := FALSE;
! FOR EACH ROW row2 IN t2 IF c1(t1,t2) AND (f1 ? c2(t2) : TRUE) {
! BOOL f2 := FALSE;
! FOR EACH ROW row3 IN t3 IF c2(t2,t3) AND (f1&&f2 ? c3(t3) : TRUE) {
! IF (f1&&f2 ? TRUE : (c2(t2) AND c3(t3))) {
! result := row1 || row2 || row3; OUTPUT result; }
! f2 := TRUE; f1 := TRUE; }
! IF (!f2) {
! IF (f1 ? TRUE : c2(t2) && c(t1,t2,NULL)) {
! result := row1 || row2 || NULL; OUTPUT t; }
! f1 := TRUE; } }
! IF (!f1 && c(t1,NULL,NULL)) {
! result := row1||NULL||NULL; OUTPUT t; } }
Ø 经过测试,三张10000行的表用外连接平均比内
连接慢0.01s,内连接效率高于外连接。
70. MySQL 优化器概述
Ø MySQL优化器属于RBO(基于规则的优化器),
5.1版本后带有少量的CBO(基于 销的优化器)
特性。
Ø MySQL优化器缺陷:
n 不支持函数索引:WHERE func(col) = x 无法使用col字段上
的索引
n 不支持索引过滤 (Index Filter) 但支持索引覆盖扫描:
n SELECT col1,col2,col3,col4 FROM t WHERE col1 > x AND col2 < y AND col3 >z; 无法利用
(col1,col2,col3)索引过滤col2和col3,需要回表查询。
n SELECT col1,col2,col3 FROM t WHERE col1 > x AND col2 < y AND col3 >z; 可以利用
(col1,col2,col3)索引扫描到col1,col2,col3的值不用回表。
n 无法自动优化子查询:MySQL无法将子查询优化为JOIN方式,
而是将子查询存为临时表(无索引),在外层SQL需要时调
用临时表数据进行匹配,这是效率非常低的执行方式,所以
尽量避免在SQL中使用子查询。
71. MySQL 优化器统计信息
Ø MySQL采集的统计信息:每一索引列的基数,
即索引中每一列中唯一值的个数,由此可以判定
一个列给它一个值大概可以过滤多少数据
Ø 例如某列基数为1000,表示随机给一个值,通过
索引可以过滤999/1000的数据
Ø show index from table可以看到表上每个列的基
数
! +--------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
! | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
! +--------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
! | orders | 0 | PRIMARY | 1 | o_orderkey | A | 1493508 | NULL | NULL | | BTREE | |
! | orders | 1 | orders_fk1 | 1 | o_custkey | A | 213358 | NULL | NULL | | BTREE | |
! | orders | 1 | orders_dt_idx | 1 | o_orderdate | A | 4567 | NULL | NULL | | BTREE | |
! +--------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
72. MySQL 优化器判定算法
Ø MySQL利用索引的原则:尽可能用主键索引>尽
可能筛去更多的数据>尽可能使用⻓长度小的索引>
尽可能使用更多索引列。
! idx_Col1索引⻓长度368,过滤基数9000
! idx_Col3索引⻓长度128,过滤基数3000
! idx_Col1_Col2索引⻓长度768,过滤基数11000
! idx_Col2_Col3索引⻓长度255,过滤基数 9000
! SELECT Col1, Col2, Col3 FROM t WHERE col1 = x AND col2 = y AND col3
= z;
! 优先使用idx_Col2_Col3索引,因为过滤基数差不多,索引⻓长度小得多。
! SELECT Col1, Col2, Col3 FROM t WHERE col1 = x AND col3 = z;
! 优先使用idx_Col1索引,因为col1过滤基数远大于col3,而idx_Col1_Col2因
为索引⻓长度⻓长的多过滤基数却相近则不被使用
74. 如何平衡查询性能和修改代价
Ø 索引对修改数据的影响有多大?
Ø 为每个列建单列索引?
Ø 字符串类型怎么建索引 算?
Ø 怎么利用好前缀索引?
Ø JOIN还有排序怎么办?
Ø JOIN还有WHERE条件怎么处理?
Ø 子查询怎么建索引?
Ø 数据 移该怎么处理索引?
Ø Any Questions?
76. 编写高性能SQL
Ø 不写不必要的条件(索引判定缺陷)
Ø 只选择必要的列(覆盖索引优化)
Ø 联列类型相同(类型转换速度)
Ø 计数全部用count(*)(优化器特性)
Ø 少子查询,优化为JOIN(优化器缺陷)
Ø 尽量不要使用主键排序,除非有主键作为条件
(优化器缺陷)
Ø 尽量将 杂查询拆分为简单查询(优化器缺陷)
Ø 尽量将OR查询拆分为多个SQL做UNION ALL或
在程序拼接(优化器缺陷)
Ø 批量提交修改( 少日志刷新)
78. 设计高性能Schema
Ø 主键必须是顺序插入(索引组织表特性)
Ø 可以用空间换时间多建索引(变更缓冲优化)
Ø 尽量少用唯一键(变更缓冲局限)
Ø 索引可以在SQL需要的列不多的情况下包含不在
条件中的列(覆盖索引)
Ø 尽量不要设计超过768字节需要作为查询条件的
列(索引限制)
Ø 不要设计超过4K行⻓长的表(⻚页结构限制)
80. 可选方案
Ø cp
l 直接拷⻉贝文件,只适合停机备份
l InnoDB必须拷⻉贝日志才能保证
Ø mysqldump
l MyISAM无法保证数据一致,必须锁定写入
l InnoDB可以使用—single-transation
Ø xtrabackup
l 在线备份物理文件,导出速度快,可以增量
l 前需要预处理, 时临时预处理时间⻓长
l 可以在备份完成后立刻预处理,提升 速度
Ø replication
l 搭建延时Slave,可按需导出需要的数据
l 大集群如何优化维护难题
82. 可选方案
Ø 水平拆分
l 相同拆分键的数据在一起
l 同一分区键的数据可以JOIN
Ø 垂直拆分
l 可以不分库
l 功能之间调用只能使用程序接口
Ø 中间件
l 自动分库,对应用透明
l 扩展不 活
l 发难度较大,不适合中小企业
Ø 程序分库[推荐]
l 可自定义分库规则
l 活扩展
l 无需中间件,直连数据库
84. 可选方案
Ø binlog replication
l 推荐ROW格式,绕过Parse操作
l 原生可靠
l 只能1对N模式
Ø trigger
l 用触发器记录需要的表
l 不用全库 制,容易过滤
l 可以实现任意多主库向任意多备库同步
Ø 中间件
l 从可配置主库读取binlog,过滤需要的日志部分,传输给需要
的目标库
l 活性 强
l ROW格式binlog处理速度快
l 发成本较高
86. 典型故障
Ø 不合理的Schema设计
Ø 不合理的热点数据估算
Ø 不合理的任务调度
Ø 不合理的操作