高性能MySQL _第七章_高级特性_分区表_视图_外键_触发器_存储过程_绑定变量

MySQL高级特性

主要内容

  1. 分区表
  2. 视图
  3. 外健约束
  4. 存储过程
  5. 触发器
  6. 绑定变量
  7. 字符集
  8. 全文索引
  9. 分布式(XA)事物
  10. 查询缓存

  1. 分区表

    1. 概念

      分区表是一种粗粒度的、简易的索引策略,适用于大数据量的过滤场景。对用户来说,分区表是一个独立的逻辑表,但是底层是由多个物理子表组成。

    2. 使用场景

      1. 表的数据非常大以致无法全部放到内存中,或者只在表的最后部分有热点数据,其他均是历史数据
      2. 分区表的数据更容易维护。可以删除整个分区,对单独分区优化
      3. 分区表的数据可以存储在不同的物理设备,有效的利用多个硬件设备
      4. 可以使用分区表避免某些特殊的瓶颈,例如InoDB的单个索引的互斥访问、ext3文件系统的inode锁竞争等。
    3. 自身限制

      1. 一个表只能1024个分区
      2. 在MySQL5.1中,分区表达必须是整数,或者是返回整数的表达式,MySQL5.5中,某些场景中可以直接使用列进行分区。
      3. 如果分区字段中有主键或者唯一索引,那么所有主键列和唯一索引列都必须包含进来。(即:分区字段要么不包含主键或者索引列,要么包含全部主键和索引列。)
      4. 分区表中无法使用外健约束
    4. 使用策略

      1. 全量扫描数据, 不要任何索引
      2. 索引数据, 分离热点
    5. 分区表使用注意场景

      1. NULL值会使分区过滤无效
      2. 分区列和索引列不匹配
      3. 选择分区的成本可能很高
      4. 打开并锁住所有底层表的成本可能很高
      5. 维护分区的成本可能很高
      6. 所有分区表必须使用相同的存储引擎
      7. MERGE, CSV, or FEDERATED存储引擎不支持分区
    6. 查询优化

      1. 分区表最大的优点就是优化器可以根据分区函数过滤一些分区。根据粗粒度索引的优势,通过分区过滤通常可以让查询扫描更少的数据。
      2. 在WHERE条件中带入分区列,有时候即使看似多余也要带上,可以让优化器过滤掉无需访问的分区
    7. 分区表类型

      • RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区。
        1. 当插入的记录中对应的分区键的值不在分区定义的范围中的时候,插入语句会失败
        2. Range分区中,分区键的值如果是NULL,将被作为一个最小值来处理。
      • LIST分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。
        1. 如果插入的记录对应的分区键的值不在list分区指定的值中,将会插入失败。并且,list不能像range分区那样提供maxvalue。
      • HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。这个函数可以包含MySQL 中有效的、产生非负整数值的任何表达式。
      • KEY分区:类似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL服务器提供其自身的哈希函数。必须有一列或多列包含整数值
      • COLUMN分区是5.5开始引入的分区功能,只有RANGE COLUMN和LIST COLUMN这两种分区;支持整形、日期、字符串;RANGE和LIST的分区方式非常的相似。
    8. 分区表相关命令

      查看是否支持分区表
      SHOW PLUGINS ;
      #如果 partition 的状态是ACTIVE 表示支持分区表
      partition                  | ACTIVE 
      
      创建RANGE分区
       CREATE TABLE employees ( 
           id INT NOT NULL, 
           fname VARCHAR(30), 
           lname VARCHAR(30), 
           hired DATE NOT NULL DEFAULT '1970-01-01', 
           separated DATE NOT NULL DEFAULT '9999-12-31', 
           job_code INT NOT NULL, 
           store_id INT NOT NULL 
       ) 
       PARTITION BY RANGE (store_id) ( 
           PARTITION p0 VALUES LESS THAN (6), 
           PARTITION p1 VALUES LESS THAN (11), 
           PARTITION p2 VALUES LESS THAN (16), 
           PARTITION p3 VALUES LESS THAN (21) 
       ); 
      
      创建LIST分区
      CREATE TABLE tblist (
          id INT NOT NULL,
          store_id INT
      )
      PARTITION BY LIST(store_id) (
          PARTITION a VALUES IN (1,5,6),
          PARTITION b VALUES IN (2,7,8),
          PARTITION c VALUES IN (3,9,10),
          PARTITION d VALUES IN (4,11,12)
      );
      
      创建HASH分区
      CREATE TABLE tblinhash (
          id INT NOT NULL,
          hired DATE NOT NULL DEFAULT '1970-01-01'
      )
      PARTITION BY LINEAR HASH( YEAR(hired) )
      PARTITIONS 6;
      
      创建KEY分区
      CREATE TABLE tb_key (
          id INT ,
          var CHAR(32) 
      )
      PARTITION BY KEY(var)
      PARTITIONS 10;
      

      range column

      CREATE TABLE members (
          id INT,
          joined DATE NOT NULL
      )
      PARTITION BY RANGE COLUMNS(joined) (
          PARTITION a VALUES LESS THAN ('1960-01-01'),
          PARTITION b VALUES LESS THAN ('1970-01-01'),
          PARTITION c VALUES LESS THAN ('1980-01-01'),
          PARTITION d VALUES LESS THAN ('1990-01-01'),
          PARTITION e VALUES LESS THAN MAXVALUE
      );
      

      移除表的分区

      • 使用remove移除分区是仅仅移除分区的定义,并不会删除数据和drop PARTITION不一样,后者会连同数据一起删除
      ALTER TABLE tablename
      REMOVE PARTITIONING ;
      
    9. demo

      CREATE TABLE employees (
          id INT NOT NULL,
          fname VARCHAR(30),
          lname VARCHAR(30),
          hired DATE NOT NULL DEFAULT '1970-01-01',
          separated DATE NOT NULL DEFAULT '9999-12-31',
          job_code INT NOT NULL,
          store_id INT NOT NULL
      )
      PARTITION BY RANGE (store_id) (
          PARTITION p0 VALUES LESS THAN (6),
          PARTITION p1 VALUES LESS THAN (11),
          PARTITION p2 VALUES LESS THAN (16),
          PARTITION p3 VALUES LESS THAN (21)
      ); 
      ##查看分区情况
      SELECT   PARTITION_NAME, PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_DESCRIPTION,TABLE_ROWS,SUBPARTITION_NAME,SUBPARTITION_METHOD,SUBPARTITION_EXPRESSION FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='employees';
      ### 创建索引
      alter table employees add index ix_store_id(store_id) ;
      alter table employees add index ix_job_code(job_code) ;
      
      ###插入数据
      insert into employees(id,job_code,store_id) values(1,1001,1),(2,1002,2),(3,1003,3),(4,1004,4);
      
      ###比较效果
      explain select * from employees where store_id = 3;
      explain select * from employees where store_id < 11;
      ##超过分区范围提示错误
      insert into employees(id,job_code,store_id) values(1,1001,33);
      ##增加新分区
      alter table employees add PARTITION  (PARTITION p4 VALUES LESS THAN MAXVALUE);
      ##删除分区
      alter table employees drop  PARTITION p4;
      ##拆分分区
      ALTER TABLE employees REORGANIZE PARTITION p0 INTO (
          PARTITION s0 VALUES LESS THAN (3),
          PARTITION s1 VALUES LESS THAN (6)
      );
      ##移除分区
      ALTER TABLE employees
      REMOVE PARTITIONING ;
      
    10. 合并表

      1. 概念

        合并表是一种早期的、简单的分区实现,和分区表相比有一些不同的限制,并且缺乏优化。(一种将被淘汰的技术,在未来的版本中可能被删除),合并表和merge引擎
      2. 和分区表的区别

        1. 合并表允许用户单独访问各个子表,分区表对用户来说是一个独立的逻辑表
        2. 分区表和优化器的结合更加紧密,
      3. 合并表的不足

        1. 合并表中的每一个子表行为和定义都是相同的,但是合并表在全局上并不接受这些条件限制
        2. 查询访问合并表,需要访问所有子表。而分区表能根据查询条件过滤部分分区
  2. 字符集和校对

    1. 字符集概念

      基本概念
      1. 字符(Character)是指人类语言中最小的表义符号。例如’A'、’B'等;
      2. 给定一系列字符,对每个字符赋予一个数值,用数值来代表对应的字符,这一数值就是字符的编码(Encoding)。例如,我们给字符’A'赋予数值0,给字符’B'赋予数值1,则0就是字符’A'的编码;
      3. 给定一系列字符并赋予对应的编码后,所有这些字符和编码对组成的集合就是字符集(Character Set)。例如,给定字符列表为{’A',’B'}时,{’A'=>0, ‘B’=>1}就是一个字符集;
      4. 字符序(Collation)是指在同一字符集内字符之间的比较规则;
      5. 确定字符序后,才能在一个字符集上定义什么是等价的字符,以及字符之间的大小关系;
      6. 每个字符序唯一对应一种字符集,但一个字符集可以对应多种字符序,其中有一个是默认字符序(Default Collation);
      7. MySQL中的字符序名称遵从命名惯例:以字符序对应的字符集名称开头;以_ci(表示大小写不敏感)、_cs(表示大小写敏感)或_bin(表示按编码值比较)结尾。例如:在字符序“utf8_general_ci”下,字符“a”和“A”是等价的;
    2. 系统变量

      • character_set_server:默认的内部操作字符集
      • character_set_client:客户端来源数据使用的字符集
      • character_set_connection:连接层字符集
      • character_set_results:查询结果字符集
      • character_set_database:当前选中数据库的默认字符集
      • character_set_system:系统元数据(字段名等)字符集
    3. 相关命令

      1. 查看系统支持字符集

            SHOW CHARACTER SET; #查看支持字符集
            SHOW COLLATION;     #查看支持校验
            show variables like 'collation_%';
        
      2. 设置系统字符集

        SET character_set_client = utf8 ;  
        SET character_set_connection = utf8 ;   
        SET character_set_database = utf8 ;   
        SET character_set_results = utf8 ;    
        SET character_set_server = utf8 ;  
        
        SET collation_connection = utf8 ;  
        SET collation_database = utf8 ;   
        SET collation_server = utf8 ; 
        ######### SET NAMES 命令相当与执行了  character_set_client, character_set_connection,character_set_results
        SET NAMES UTF8
        
      3. 查看系统字符集

        SHOW VARIABLES LIKE 'character%';
        STATUS;
        
      4. 查看表的默认字符集

        show create table `t1`;
        
      5. 设置表的字符集

        alter table `t1` charset=gbk;
        
      6. 查看字段字符集

        show full columns from t1;
        
      7. 修改字段字符集

        alter table t1 change `name`  `name` varchar(20) character set utf8  COLLATE utf8_bin not null default '';
        
    4. 字符集继承顺序

      1. SERVER->DB->TABLE->COLUMN
    5. 注意点

      1. character_set_client 字符集要和客户端字符集保持一致,否者多字节字符会出现乱码
      2. LENGTH函数和CHAR_LENGTH函数的区别LENGTH计算字符数,CHAR_LENGTH计算字节数,多字节字符这两个函数的结果会不一样
      3. 字符集会影响临时表的分配UTF8字符集会按最大字节数分配就算存的全是字母,也是按每个字符三个字节分配
      4. 影响索引的最长索引前缀(不同版本的MySQL最长索引前缀不同,单位按字节算)
        create table t2 (
            id int not null auto_increment primary key, 
            `name` varchar(1025) not null default '', 
            key(`name`)
        ) engine=innodb charset =utf8;
        ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
        
  3. 绑定变量

    1. 使用场合

      当查询语句的解析和执行计划生成消耗了主要的时间,那么绑定变量可以在一定程度上解决问题,因为只需要解析一次,对于大量重复类型的查询语句,
      性能会有很大的提高。
    2. 高效的原因

      1. 在服务端只需要解析一次
      2. 在服务端的某些优化器的工作只需要执行一次,因为会缓存一部分执行计划。
      3. 一二进制的方式只发送参数和句柄, 比起每次都发送ASCII码文本效率高,一个二进制的日期只需要三个字节,但如果是ASCII码则需要十个字节
      4. 仅仅是参数----而不是整个查询语句----需要发送到服务器,所以网络开销会更小。
      5. MySQL在存储参数的时候,直接将其存放在缓存中,不再需要在内存中多次复制
    3. 绑定变量安全性相对较高(任何时候都不要相信用户的数据,即使是绑定变量)

      1. 无需在应用程序中处理转义,操作更简便,大大减少了SQL注入和攻击的风险
    4. 绑定变量的优化

      1. 准备阶段

        服务器解析SQL语句,移除不可能的条件,并且重写子查询
      2. 在第一次执行的时候

        如果可能, 服务器先简化嵌套循环的关联,并将外关联转化成内关联
      3. 在每次SQL语句执行时

        1. 过滤分区
        2. 如果可能的话, 尽量移除COUNT(),MIN(),MAX()
        3. 移除常量表达式
        4. 检测常量表
        5. 做必要的等值传播
        6. 分析和优化ref、 range和索引优化等访问数据的方式
        7. 优化关联顺序
      4. 绑定变量的限制

        1. 绑定变量是会话级别的,所以连接之间不能共用绑定句柄,一旦连接断开,原来的句柄就不能使用(连接池和持久连接一定程度上缓解这个问题)
        2. 在MySQL5.1之前不能使用查询缓存
        3. 如果只是执行一次SQL,那么使用绑定变量的方式无疑比直接执行多了一次额外的准备阶段消耗,还需要一次额外的网络开销
        4. 如果总是忘记释放绑定变量资源,服务器很容易发生资源泄漏,绑定变量的SQL总数是一个全局限制
    5. 相关命令

          SET @sql := 'select * from `t1` where `name` = ?';
          PREPARE stmt_fetch FROM @sql;
          SET @name :='a';
          EXECUTE stmt_fetch USING @name;
      
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容