• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
对MySQL应用的一些总结
 

对MySQL应用的一些总结

on

  • 743 views

 

Statistics

Views

Total Views
743
Views on SlideShare
743
Embed Views
0

Actions

Likes
3
Downloads
35
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    对MySQL应用的一些总结 对MySQL应用的一些总结 Presentation Transcript

    • MySQL OptimizationMySQL架构设计与优化最佳实践 彭立勋 http://www.PengLiXun.com/ PengLiXun@gmail.com
    • Topics of Discussion(上午)l  MySQL缺陷与适用场景l  MyISAM vs InnoDBl  MyISAM与InnoDB性能调优l  MySQL Server性能调优l  MySQL Join算法l  MySQL 优化器特性l  索引设计杂谈
    • Topics of Discussion(下午)l  编写高性能SQLl  设计高性能Schemal  数据备份与 策略l  数据拆分方案l  制设计方案l  典型故障案例分析l  构建高性能高可用可扩展MySQL集群
    • Next TopicMySQL缺陷与适用场景
    • MySQL架构
    • MySQL缺陷Ø  MySQL没有Hash Join à 不适合无索引大数据 量数据分析Ø  MySQL没有完整的CBO à 不可依赖MySQL选 择最优的执行计 ,不可依赖MySQL自行优化 SQLØ  MySQL没有备块级 制 à 不可依赖MySQL保证 备库的实时一致性Ø  MySQL无法有效利用主机资源 à 单机单实例会 严重的浪费机器性能
    • MySQL适用场景ü  应用会产生庞大连接数(Thread)ü  可以依赖索引完成的数据分析(Covering Index)ü  高并发查询(MyISAM)ü  短小的在线事务处理(InnoDB)ü  简单条件查询(HandlerSocket)ü  数据拆分(Free)
    • Next TopicMyISAM vs InnoDB
    • MyISAM的优势和劣势 优势 劣势小内存下更快速的查询:   数据文件容易损坏:  因为没有复杂的MVCC多版本控 因为数据回写机制没有原子性制机制 保证更小的数据文件:   没有事务保证  因为数据文件中没有额外的行锁和事务信息非常容易冷备份:   只有索引缓存因为每张表三个文件,没有额外的全局信息,拷贝文件即可备份 表级锁,并发差
    • InnoDB的优势和劣势 优势 劣势行级锁,并发高:   小内存下纯读应用不如MyISAM只锁定被访问到的行,并不影 快响对不同行的操作。ACID事务保证 备份操作更复杂:   因为存在事务信息,多版本信 息,不能简单的拷贝数据文件。 但是支持热备份。所有数据文件均可缓存:   更占用磁盘空间:  InnoDB主键索引即数据,缓存 因为行结构中包含事务信息和索引就包括了缓存数据 行锁信息,另外有UNDO和REDO 事务日志读写互不阻塞:  得益于MVCC多版本控制,读数据并不需要锁定修改,可以在UNDO日志中找到旧版本。
    • 索引对比 MyISAM InnoDBB-­‐Tree结构,不能自动Balance B+Tree结构,自动Balance堆表:   索引组织表:  数据文件独立于索引,数据文 数据文件以主键顺序组织,主件以插入顺序组织,以物理位 键即数据,非主键索引通过主置为引用键,索引通过物理位 键查找数据行。所以主键插入置查找数据行。 无序时性能极差。 支持自适应哈希:   当InnoDB发现表上经常存在某 些唯一键上的KV查询时,会自 动把这部分数据生成到自适应 哈希表中,可进行KV查询优化。 主键索引包含事务信息:   主键索引上唯一确定了一行数 据,所以事务信息包含在主键 索引上。如果没有显示定义主 键索引,将自动建立隐含主键。
    • MyISAM场景ü  数据仓库:大量读,批量写,可共享数据文件ü  日志系统:只有插入没有修改,简单查询ü  读为主的应用:没有写或写 少,几乎不阻塞读ü  低并发的应用:表锁基本不影响并发ü  大数据批量导入:避免InnoDB索引组织表主键 乱序时插入慢
    • InnoDB场景ü  高并发的应用:例如消息队列ü  可靠性要求高的应用:例如用户登陆信息ü  数据一致性要求高,宕机可 :例如用户数据ü  要求事务和约束的应用:例如有数据 联的系统ü  需要高性能缓冲写的应用:例如短时间内大量 UPDATE
    • 同时使用MyISAM / InnoDBØ  不可共享缓存空间Ø  SQL包含 表将失去事务意义总之不推荐这 表同时存在同一实例,除非: 表没有 联,MyISAM表只做备份冗余。但是,Master用InnoDB,Slave用MyISAM某些情况下是不错的方案。
    • Next TopicMyISAM和InnoDB的优化
    • MyISAM优化 l  INSERT 优化l  Key Buffer 优化
    • MyISAM 插入Ø  定⻓长表优于变⻓长表,即尽可能不定义变⻓长字段Ø  数据存储按插入顺序,除非删除了数据产生的空 洞可以插入新行 或 使用了并发插入Ø  可以加大bulk_insert_buffer_size变量,采用 ”INSERT INTO table VALUES (),(),...” 的批量插 入语法,或者采用LOAD DATA语法
    • MyISAM 并发插入虽然MyISAM是表锁,但是如果只在数据文件末尾插入数据,是可以并发的,通过concurrent_insert变量控制:n  0 – (Off):不允许并发插入n  1 – (Default):如果数据文件没有空洞,可以在数据文件末尾并发 插入n  2 – Enable:如果表在被使用则在数据文件末尾并发插入,如果 表没有被使用则一样在文件中找空洞插入 [建议]
    • Key Buffer 原理
    • 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(未回写的脏缓冲块)
    • Key Buffer 监控Ø  命中率 = (requests - reads) / requestsØ  利用率 = key_blocks_used / (key_blocks_used + key_blocks_unused)Ø  赃⻚页率 = key_blocks_not_flushed / (key_blocks_used + key_blocks_unused)
    • Key Buffer 注意key_buffer_size不能 闭,因为至少mysql系统库全部用的MyISAM表,就算整个实例都是InnoDB表,也应该设置key_buffer_size。
    • 多段 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)
    • 预载入 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)
    • Key Buffer 建议最好可以保证Key Buffer Size大于目前所有需要访问的表MYI文件大小总和。如无法保证则一般分三个区给不同业务类型的表:n  静态缓冲区, 少或不修改的表,这个区的Key Buffer访问没有 写锁,都是Shared Read Lock。n  修改缓冲区,大量修改或UPDATE的表,这个区的Key Buffer竞 争严重,限制竞争在一个区。n  普通缓冲区,除大量修改和只读表以外的正常读写比例的表。
    • 刷新 Key Buffer内存中缓存的索引块,有时候并不会及时刷新到磁盘上,所以对于正在运行的数据表的索引文件(MYI)一般都是不完整的。如果此时拷⻉贝或者移动这些索引文件。多半会出现索引文件损坏的情况。可以通过Flush table命令来将Key Buffer中的block都flush到磁盘上。!  mysql> flush tables;!  +------------------------+----------+!  | Variable_name | Value |!  +------------------------+----------+!  | Key_blocks_not_flushed | 0 | #所有修改的block都已经被flush了!  | Key_blocks_unused | 0 |!  | Key_blocks_used | 14497 |!  | Key_read_requests | 38333936 |!  | Key_reads | 207 |!  | Key_write_requests | 8819898 |!  | Key_writes | 1255245 |!  +------------------------+----------+
    • InnoDB优化l  Buffer Pool 调优 l  日志 调优 l  XtraDB调优
    • 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。
    • InnoDB 文件结构
    • InnoDB 数据文件组织Ø  最基本的修改单位是RowØ  最基本的IO单位是Page,包含2个以上RowØ  最基本的分配单位是Extent,包含64个PageØ  InnoDB的索引都是指到Page no为止,为了B- Tree保持高效,InnoDB要求一个Page内至少有 2行数据,所以我们建议每行数据设计⻓长度不要 超过4K,这样我们可以方便的 移到最平衡的 8K⻚页大小。
    • InnoDB 数据文件组织
    • InnoDB 索引结构
    • InnoDB 主线程
    • Buffer PoolInnoDB最重要的一块内存就是Buffer Pool,它包含了几乎所有InnoDB数据和索引的缓冲,主要有:n  数据缓存(主键缓存)n  索引缓存(非主键索引缓存)n  自适应哈希n  数据字典n  ⻚页哈希等
    • Buffer Pool 设置innodb_buffer_pool_size设置Buffer Pool的大小。建议将除了连接使用的内存,操作系统使用的内存之外的全部内存给Buffer Pool,不要靠操作系统的OS Cache来缓冲缓存数据。经验参考值:n  48G内存:32G Buffer Pooln  32G内存:20G Buffer Pooln  24G内存:16G Buffer Pooln  16G内存:10G Buffer Pool
    • Buffer Pool 赃⻚页比例Buffer Pool同时担任缓冲和缓存工作,因此BufferPool中会产生赃⻚页,即在内存中修改了但未刷新到磁盘上的⻚页。innodb_max_dirty_pages_pct变量可以配置最多允许多少比例的赃⻚页在内存中,超过比例将触发刷新。经验参考值:n  75%适用于绝大部分情况,Google/Facebook/Alibaba均使用n  5%适用于非常在意宕机快速 的情况,Taobao/Alipay使用
    • InnoDB 事务安全Ø  REDO LOG:所有变更内容全部写入REDO LOG。一 旦数据库Crash,将redo中已经标记为commit状态的事 务全部重做到数据文件,将没有标记为commit的事务在 数据文件中回 。Ø  UNDO LOG:所有数据被修改的旧版本数据和版本号 写入undo,当需要回 事务时,在undo中找到旧版本 信息,覆盖数据文件。Ø  Double Write Buffer:所有的⻚页级回写,都先将⻚页写 入Double Write Buffer区域, 认CheckSum与内存中 的⻚页一致,再正式写入数据文件中,如果数据库Crash, 数据文件中的⻚页没有回写完成,可以从Double Write Buffer中读取正 的⻚页重写。
    • InnoDB 日志
    • Log BufferØ  事务安全使得InnoDB会产生事务日志,包括 REDO和UNDO。日志回写到磁盘会有一个Log Buffer缓冲日志写Ø  innodb_log_buffer_size设置事务日志缓冲大小Ø  经验参考值: n  默认只有1M,存在大事务或者高并发情况,建议设置8~16M
    • InnoDB 事务提交Ø  Log Buffer中缓冲的日志在检查点或事务提交时 回写文件。Ø  Buffer Pool中的⻚页在检查点时回写磁盘。Ø  innodb_flush_log_at_trx_commit控制回写: n  0: 每秒刷新日志到文件(不是磁盘) n  1: 每次事务提交刷新日志到磁盘 [default] n  2: 每次事务提交刷新日志到文件,每秒同步到磁盘 [建议]
    • 日志大小设置Ø  更大的事务日志意味着什么? n  可以记录更大的事务信息 [可以重做更大的事务] n  可以记录更⻓长的事务历史 [可以重做更多的事务] n  更少的检查点 [ 少磁盘IO] n  更⻓长的 时间 [宕机重启时间更⻓长]Ø  经验参考值: n  64M的日志5分钟以内就可以 n  1G的日志全部重做需要30分钟以上 n  我们设置为3个1G的日志
    • 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锁结构:通过为每个⻚页生成一个锁定位图,判 定行是否被锁定,每⻚页的第一行和最后一行是系统行, 如果被锁定说明整⻚页被锁。
    • 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中的最小事务号,就是 不可⻅见的。
    • 自适应哈希Ø  自适应哈希是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
    • 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
    • InnoDB 优化实践ü  尽可能使用小的主键: 少非主键索引大小ü  按主键顺序插入数据:避免主键节点分裂ü  加大日志大小:避免过多的检查点ü  避免大事务回 :会产生大量的随机IO,拆分事 务ü  避免零散的插入:尽可能批量插入ü  尽量 用前缀索引:InnoDB不会压缩索引
    • InnoDB 其他重要变量Ø  innodb_additional_mem_pool_size:内部元信 息缓存,16M足以胜任任何情况Ø  innodb_support_xa:是否支持 段提交协议, 没有必要 启, 闭可获得10%的性能提升。
    • 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
    • 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表结构
    • Next TopicMySQL Server 性能调优
    • 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 | # 表曾经被打 多少次!  +--------------------------+-------+
    • 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 | !  +----------+--------------+--------+-------------+
    • Query Cache 介绍Query Cache是独立于存储引擎的SQL级缓存,它实际上是SQL文本的MD5值和SQL执行结果的哈希键对。因此Query Cache的使用受到很大限制:n  SQL文本必须完全相同,包括大小写,空格n  存在不 定函数的SQL不被缓存,例如NOW()n  PREPARE方式执行的SQL不被缓存n  自定义函数,存储过程,视图均不能被缓存
    • 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的结果集
    • 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 | # 当前使用的内存块的数量!  +-------------------------+----------+
    • 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
    • Thread Cache 介绍每个连接到MySQL都需要创建一个线程,ThreadCache就缓存了已经断 的连接线程描述符,如果创建线程前检测到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))); //没有可用空闲线程则创建一个新的线程!  }!  }
    • Thread Cache 配置Ø  经验建议值: n  thread_cache_size = 1024 适应绝大部分场景 n  并发连接数很少时,相应降低配置Ø  优化建议: n  如果threads_created增⻓长很快,应该调大thread_cache_size 的值
    • 连接数Ø  配置变量: 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,一般不 需要多少线程级内存。
    • Sort Buffer 介绍Ø  每个线程需要排序的时候都会申请一块Sort Buffer,线程第一次使用的时候分配,连接断 后线程不销毁则内存不释放。Ø  如果要排序的数据大于Sort Buffer将会用归并排 序法分块排序,超出内存部分写入磁盘暂存。Ø  sort_buffer_size 根据需要排序的数据集大小而 定,可以按照Session在连接内重新设定。
    • Sort Buffer 监控Ø  Sort_merge_passes:归并排序次数,这个值很大说明 Sort Buffer不 ,很多排序数据写到磁盘上了Ø  Sort_rows:被排序数据的行数Ø  Sort_range:通过索引选择了一个范围的数据后排序Ø  Sort_scan:通过全表扫描进行排序的次数,这个值很 大应该优化索引避免排序
    • Join / Read BufferØ  join_buffer_size:JOIN时如果不能用到索引就 会使用Join Buffer进行JOIN,最好优化索引避免 使用Join Buffer。Ø  read_buffer_size:全表扫描时缓存读取的数 据,最好通过索引避免全表扫描。
    • 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 |!  +----+-------------+-------+------+---------------+------+---------+-------------- +------+---------------------------------+
    • 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的值
    • Next TopicMySQL Join 算法
    • 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
    • 内连接Ø  假定我们有一个如下形式的表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的行数
    • 外连接Ø  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,内连接效率高于外连接。
    • Next TopicMySQL 优化器特性
    • 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中使用子查询。
    • 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 | |!  +--------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
    • 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因 为索引⻓长度⻓长的多过滤基数却相近则不被使用
    • Next Topic索引设计杂谈
    • 如何平衡查询性能和修改代价Ø  索引对修改数据的影响有多大?Ø  为每个列建单列索引?Ø  字符串类型怎么建索引 算?Ø  怎么利用好前缀索引?Ø  JOIN还有排序怎么办?Ø  JOIN还有WHERE条件怎么处理?Ø  子查询怎么建索引?Ø  数据 移该怎么处理索引?Ø  Any Questions?
    • Next Topic编写高性能SQL
    • 编写高性能SQLØ  不写不必要的条件(索引判定缺陷)Ø  只选择必要的列(覆盖索引优化)Ø  联列类型相同(类型转换速度)Ø  计数全部用count(*)(优化器特性)Ø  少子查询,优化为JOIN(优化器缺陷)Ø  尽量不要使用主键排序,除非有主键作为条件 (优化器缺陷)Ø  尽量将 杂查询拆分为简单查询(优化器缺陷)Ø  尽量将OR查询拆分为多个SQL做UNION ALL或 在程序拼接(优化器缺陷)Ø  批量提交修改( 少日志刷新)
    • Next Topic设计高性能Schema
    • 设计高性能SchemaØ  主键必须是顺序插入(索引组织表特性)Ø  可以用空间换时间多建索引(变更缓冲优化)Ø  尽量少用唯一键(变更缓冲局限)Ø  索引可以在SQL需要的列不多的情况下包含不在 条件中的列(覆盖索引)Ø  尽量不要设计超过768字节需要作为查询条件的 列(索引限制)Ø  不要设计超过4K行⻓长的表(⻚页结构限制)
    • Next Topic备份与 策略
    • 可选方案Ø  cp l  直接拷⻉贝文件,只适合停机备份 l  InnoDB必须拷⻉贝日志才能保证Ø  mysqldump l  MyISAM无法保证数据一致,必须锁定写入 l  InnoDB可以使用—single-transationØ  xtrabackup l  在线备份物理文件,导出速度快,可以增量 l  前需要预处理, 时临时预处理时间⻓长 l  可以在备份完成后立刻预处理,提升 速度Ø  replication l  搭建延时Slave,可按需导出需要的数据 l  大集群如何优化维护难题
    • Next Topic数据拆分方案
    • 可选方案Ø  水平拆分 l  相同拆分键的数据在一起 l  同一分区键的数据可以JOINØ  垂直拆分 l  可以不分库 l  功能之间调用只能使用程序接口Ø  中间件 l  自动分库,对应用透明 l  扩展不 活 l  发难度较大,不适合中小企业Ø  程序分库[推荐] l  可自定义分库规则 l  活扩展 l  无需中间件,直连数据库
    • Next Topic 制设计方案
    • 可选方案Ø  binlog replication l  推荐ROW格式,绕过Parse操作 l  原生可靠 l  只能1对N模式Ø  trigger l  用触发器记录需要的表 l  不用全库 制,容易过滤 l  可以实现任意多主库向任意多备库同步Ø  中间件 l  从可配置主库读取binlog,过滤需要的日志部分,传输给需要 的目标库 l  活性 强 l  ROW格式binlog处理速度快 l  发成本较高
    • Next Topic典型故障案例分析
    • 典型故障Ø  不合理的Schema设计Ø  不合理的热点数据估算Ø  不合理的任务调度Ø  不合理的操作