zoukankan      html  css  js  c++  java
  • MYSQL总览

    个人总结

    范式名词解释

    函数依赖:若在一张表中,在属性(或属性组)X的值确定的情况下,必定能确定属性Y的值,那么就可以说Y函数依赖于X,写作 X → Y
    
    如:学生姓名函数依赖于学号,写作 学号 → 姓名   但是存在相同姓名,所以学号函数不依赖姓名
    
    码:一个表中,可以唯一决定一个元组的属性“集合”。而主键则是可以唯一决定元组的‘某个属性’
    
    例如:在成绩表中(学号,课程号)合起来叫一个码,而分开看学号是主键,课程号也是主键
    
    非主属性:不属于码的属性
    
    主属性:属于码的属性
    
    候选键:指每个都不一样的、非空的那几个属性,有着潜在的主键意义。  比如一个表中的课程号学号,系别号等等(多个构成一组候选键)。
    View Code

    第一,二,三范式解决的是非主属性的关系。
    BC 范式解决的是主属性的关系;

    第一范式 1NF:字段(列)不可再分,数据库表中的所有字段值都是不可分解的原子值
    例如 地址将省市县存入一个字段就不符合第一范式,我们需要将省市县分别存入不同的字段

    第二范式:保证每张表只表示一件事情 就是完全依赖[id1,id2]->c保证每张表只表示一件事情 ,没有部分依赖;【非主属性不能依赖于主键的一部分,要完全依赖于主键】
    例如:一张表存在学号,姓名、课程、成绩,不符合第二范式(学号和课程组成了一组候选键,成绩依赖组候选键的课程,却不依赖学号这是典型的部分依赖)

    第三范式没有传递依赖保证每列都和主键直接相关【非主属性之间的依赖】(不能有a->b->c 这种一张表c依赖b而b又依赖a的情况)
    例如:商品名,单价,数量,总金额:    “总金额”项可以通过“单价”和“数量”运算得出,存在函数依赖关系,不满足3NF(有时候还是有必要的)

    BC范式: 解决部分主键依赖于非主键部分。每个表中只有一个候选键

    常用的关系型数据库:

    int(5)和vachar(20)的区别
    在int中长度只是与显示有关系,而且在在零填充的情况下:
    在zorefill的情况下:存储的数字小于5位那么会用零填充,超过等于五位则原样显示

    在vachar中20在mysql5.0+是20个字符,以下是20个字节(现在基本不用5-的版本了)
    注意长度只是在控制台(如windows的黑窗口或者xshell等控制台有效,网页等没有效果)

    char 定长 超出长度会被截取 适合存储很短的字符,或者所有值都接近一个长度 长度不足活用空格填充
    对于经常变更的数据char比varcahr更好cahr不容易产生碎片
    对于非常短的列 char比varchar在存储空间上更有效率
    只分配真正需要的空间,更长的列会消耗更多的内存
    尽量避免使用blob、text类型,查询会使用临时表导致严重的性能开销
    日期和时间类型
    尽量使用TIMESTAMP比DATETIME空间效率要高

    连接数据库
    最简单 mysql -u root -p 密码
    带远程: mysql -h 193.168.124.1 -P 3306 -u root -p 密码 -b

    窗口操作界面时:
    退出mysql: quit、exit、q
    取消操作: c
    结束: ;或者g

    数据库操作:

    修改数据库密码:set password for root@localhost = password('newpassword'); 
    查看当前数据库字符集: show variables like 'character_set_%';
    查看字符集排序设置: show variable like 'collation_%';
    查看表信息: show table status G;
    查看数据表字符集: show table status from 库名 like '%表名%';
    查看列的字符集: show full columns from 表名;
    查看支持的字符集: show cahrset; 或者 show char set;
    查看系统中的字符集: show character set;
    查看校对集: show collation [like '字符串']
    临时修改服务器级别的字符集: set global character_set_server=utf8;
    超简单的设置字符集: set names gbk 代替了设置character_set_client,XX_results, XX_connection
    修改表级别字符集: alert table table_name default charset utf-8;

    show variables like "%char%";

     show variables like "%coll%";

    查看数据库: show databases [like '%moodl_';];
    创建数据库: create database dbname [default character set utf8];
    较全: create database if not exists dbname charset=gbk collate gbk_chinese_ci;

    DEFAULT CHARACTER SET utf8 :   代表的是将该库的默认编码格式设置为utf8格式。
    COLLATE utf8_general_ci :     代表的是数据库校对规则

    注意:如果本级没有设置字符集,默认为上一级的字符集 如在这个数据库建表没有设置字符集,那么默认就是这个数据库的字符集


    删除数据库: drop database [if exists] dbname;
    修改数据库: alter database dbname charset=gbk collate gbk_chinese_ci;
    选择数据库: use dbname;
    查看选择的数据库: select database();
    查看版本: select version();
    创建数据表: create table [if not exists] table_name(字段名 字段类型,字段名 字段类型,....);
    查看数据表: show tables [like '条件'];
    查看表结构: desc|describe table_name G; 或者show columns from 库名.表名
    查看建表语句: show create table table_name;
    删除数据表: drop table [if exists] table_name;
    修改表: alter table 表名 动作(add,modify,drop,change,rename as) 修改内容;
    修改表的字段名及类型: alter table table_name change 旧字段名 新字段名 字段类型 约束条件;
    修改表的字段类型: alter table 表名 modify 字段名 字段类型; change可以修改字段名modify不可以
    添加字段: alter table 表名 add 新字段名 字段类型 first|after 已有字段名
    删除字段: alter table 表名 drop 字段名;
    修改表名: alert table 旧表名 rename as 新表名;
    修改表的字符集: alter table 表名 default character set utf8;
    注意:如果改了表的字符集,字段的字符集时不会改变的,必须手动取更改!!!
    复制表结构: create table 表名 like 旧表名
    复制表结构及数据: create table 表名 select 字段列表或* from 旧表名 where条件 order by子句 limit 子句

    查看默认的引擎: show variables like 'default_storage_engine';
    查看所有引擎: show engines;


    数据操作:
    数据插入: insert into table_name(filed1, filed2, ...) values(values1, values2, ...);(字段名无需加引号,值需要)

    insert into table_name set filed1=value1,filed2=value2,...;
    insert into table_name values(value1,value2, ...);

    insert into 表名 select *|字段列表 from 其它表 where条件 order by 字段 asc|desc limit 起始记录,记录数

    数据查看: select filed1,filed2,... from table_name where ...;

    //从句顺序
    select---form---where---group by---having---order by---limit

    查询的group by having的用法  1、group by 必须配合聚合函数使用,2、表中某个字段存在相同值的时候(如user表中的班级字段,部门字段等)

    SELECT *|字段名, 聚合函数(字段名)
    FROM 表名
    WHERE 字段名 条件 值
    GROUP BY 字段名;

    例子:user表  user_no(员工编号),dept_no(部门编号)、from_time(入职时间) go_time(离职时间  默认9999-01-01表示在职)

    每个部门有多少名在职员工

    1、筛选在职员工 where go_time='9999-01-01';
    2、对部门进行分组group by dept_no
    3、对员工进行计数 count(user_no)
    
    SELECT
      dept_no as 部门,
      count( user_no) as 人数
    FROM
      user_dept 
    WHERE
      go_time = '9999-01-01' 
    GROUP BY
      dept_no

    having是将上面的分组查询出来在进行果过滤

    查出员工人数大于30000的部门

    departments  为部门表;
    SELECT
        ( SELECT d.dept_name FROM departments d WHERE du.dept_no = d.dept_no ) AS 部门,
        count( du.user_no ) AS 人数 
    FROM
        dept_user as du 
    WHERE
        du.go_time = '9999-01-01' 
    GROUP BY
        du.dept_no 
    HAVING
        count( du.use_no ) > 30000 

    数据更改: update table_name set filed1=value1, filed2=value2, ... where ...;

    数据删除: delete from table_name where ...; 不加条件全删

    全部删除数据: truncate table user;

    数据替换: replace into 表名 set 字段1=值1,字段2=值2,…… 冲突会删除数据慎用!!

    关联更新:

    update tablea,tableb set tablea.c1 =tableb.c1,tablea.c2=tableb.c2 where tablea.id=tableb.id
    update a INNER JOIN b ON a.id =b.id SET a.c1=b.c1,a.c2=b.c2 WHERE ...

    例子:将b表中的age>50 的c1 c2 更新到a表中对应的C1C2    表中字段: A(id sex c1 c2) B(id age c1 c2)

    update a,b SET a.c1=b.c1,a.c2=b.c2 WHERE a.id=b.id and b.age>50
    update a JOIN b ON a.id=b.id SET a.c1=b.c1,a.c2=b.c2 where b.age >50

    关联查询: 交叉连接(cross join)
    select * from a,b[,c] 或者 select * from a cross join b(cross join c)
    内连接(inner join 或者join) 取并集
    1、等值连接 select * from a inner join b on a.id=b.id
    2、不等值连接 select * from a inner join b on a.id>b.id
    3、自连接 select * from a as T1 inner join a as T2 ON T1.id=T2.pid

    外连接(left join 和right join) 取补集
    select * from a left join b on a.id=b.id
    联合查询(union 和 union all)
    union 就是把多个结果集合集中一起,union前的结果为基准。注意联合查询列数要相等,相同的列数会合并
    union all 不会合并重复数据 效率低于union
    select * from a union select * from b union ...

    全连接(full join) mysql不支持全连接 可以使用 left join union right join联合使用
    select * from a left join b ON a.id=b.id UNION select * from a right join b ON a.id=b.id
    嵌套查询(条件查询 子查询) select * from a where id in(select id from b) 效率不高

    mysql优化(硬件,软件、配置,架构)

    mysql字段优化

    mysql索引优化

    查询语句优化

    1、定位慢查询sql:

    查询优化: 查找分析慢的原因、优化查询过程中的数据访问、优化长和难的查询语句、优化特定类型的查询语句
    查找分析慢的原因:
      ①记录慢查询日志 需要开启慢查询日志 (slow_query_log=on)上面mysql优化连接有详细的介绍
    分析查询日志 不建议直接打开慢查询日志直接进行分析浪费时间和精力可以使用pt-query-digest工具进行分析
    (pt-query-digest 安装及使用 https://www.cnblogs.com/sc-xm/p/4288323.html)

    ②查看sqp索引的使用情况show status like 'Handler_read%';       #详情在优化sql索引里有介绍  

    ③使用 show profile(set profiling=1;开启),开启后会将服务器上的执行的所有语句会检测消耗的时间,存到临时表中
    步骤 黑窗口进入mysql set profiling=1 show profiles 然后等mysql的语句执行(这里我们可以selet*from wy_area 执行一条) 再执行show profiles
    显示如下:
    mysql> show profiles;
    +----------+-----------+-----------------------+
    | Query_ID | Duration | Query |
    +----------+-----------+-----------------------+
    | 1 | 1.0868975 | select * from wy_area |
    +----------+-----------+-----------------------+
    1 row in set
    然后:show profile for query 1;(这里的1是临时表的Query_ID)查看具体慢的原因


    ④使用show status; 返回一些计数器。show global status 查看服务器级别的所有计数 有时候可以更具这些计数猜出那哪些操作代价较高

    ⑤使用 show processlist 查看线程 找到是否有大量不健康的线程

    ⑥使用explain 分析单条sql语句
    mysql> explain select * from wy_area; desc select * from wy_area;也一样
    +----+-------------+---------+------+---------------+------+---------+------+------+-------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+---------+------+---------------+------+---------+------+------+-------+
    | 1 | SIMPLE | wy_area | ALL | NULL | NULL | NULL | NULL | 3932 | |
    +----+-------------+---------+------+---------------+------+---------+------+------+-------+
    1 row in set

    mysql>

    2、优化步骤:

    先说明如何定位低效率的sql语句。然后更具sql语句可能低效的原因做排查,

    先从索引着手,如果索引没有问题考虑以上几个方面:
    数据访问问题,
    长难度的查询问题
    还是一些特定的优化问题

    避免查询不需要的记录,使用limit解决
    避免多表关联时用select*返回全部列,指定需要的列
    避免总是取出全部列,select*会让优化器无法完成索引覆盖扫描的优化
    避免重复查询相同的数据,可以缓存数据,下次直接读取缓存
    是否扫描额外的记录。使用explain来进行分析。如果发现查询需要扫描大量的数据但只返回少数的行可以通过以下优化:
    1、使用索引覆盖扫描,把所有的有用的列都放到索引中,这样存储引擎不需要回表获取对应行就可以返回结果
    2、翻遍数据结构,修改数据表范式
    3、重写sql语句,让优化器可以更优的方式进行查询

    优化索引的规则


    优化长难的语句

    1、将一个大的查询分为多个小的相同的查询(删1000万条数据。可以一次删除一万暂停一会在删一万条,避免锁表节省开销)
    2、分解关联查询,可以将一条关联语句分解成多条sql来执行(让缓存的效率更高。单个查询可以减少锁竞争)
    3、大量复杂的sql语句拆分成多个小的sql语句
    4、在应用层做关联可以更容易对数据库进行拆分,查询效率大幅提升,较少的冗余记录查询

    优化特定类型的查询语句
    优化count()查询 count(*)会忽略所有的列比count(列名)快
    在MyISAM中没有where条件的count(*)非常快,当有where条件时不一定比其他的引擎快
    可以使用explain查询近似值替代count(*)
    增加汇总表,每次增减数据修改汇总表
    使用缓存

    优化关联查询
    确定ON或者usingu sing(id)等价于on a.id=b.id
    确保group by和order by中只有一个表中的列(避免order by b.id,a.name DESC),这样mysql才可能使用索引
    优化子查询 尽量用关联查询来替代子查询

    优化group by 和distinct
    这两种查询可使用索引来优化,是最有效的优化方法
    关联查询中,使用标志列进行分组的效率会更高
    如果不需要group by 排序 可以加上 group by null,mysql不再进行文件排序(否则可能会)
    with rollup 超级聚合,可以挪到应用程序处理
    优化limit分页:  limit数据量大的时候查询效率低 我们可以查询时记录上次最大的id limit 0,100 where id > 上次的id(可能不太准确) 100万数据查询优化有介绍


    优化union查询 有union all 替代 union 在应用层面在筛除重复的数据

    高扩展和高可用
    分库分表总结

    单库单表 
    
    单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到。 
    
    
    单库多表 
    
    随着用户数量的增加,user表的数据量会越来越大,当数据量达到一定程度的时候对user表的查询会渐渐的变慢,从而影响整个DB的性能。如果使用mysql, 还有一个更严重的问题是,当需要添加一列的时候,mysql会锁表,期间所有的读写操作只能等待。 
    
    可以通过某种方式将user进行水平的切分,产生两个表结构完全一样的user_0000,user_0001等表,user_0000 + user_0001 + …的数据刚好是一份完整的数据。 
    
    
    多库多表 
    
             随着数据量增加也许单台DB的存储空间不够,随着查询量的增加单台数据库服务器已经没办法支撑。这个时候可以再对数据库进行水平区分。 
    
    
    分库分表规则 
    
             设计表的时候需要确定此表按照什么样的规则进行分库分表。例如,当有新用户时,程序得确定将此用户信息添加到哪个表中;同理,当登录的时候我们得通过用户的账号找到数据库中对应的记录,所有的这些都需要按照某一规则进行。 
    路由 
    
             通过分库分表规则查找到对应的表和库的过程。如分库分表的规则是user_id mod 4的方式,当用户新注册了一个账号,账号id的123,我们可以通过id mod 4的方式确定此账号应该保存到User_0003表中。当用户123登录的时候,我们通过123 mod 4后确定记录在User_0003中。 
    分库分表产生的问题,及注意事项 
    
    1.   分库分表维度的问题 
    
    假如用户购买了商品,需要将交易记录保存取来,如果按照用户的纬度分表,则每个用户的交易记录都保存在同一表中,所以很快很方便的查找到某用户的购买情况,但是某商品被购买的情况则很有可能分布在多张表中,查找起来比较麻烦。反之,按照商品维度分表,可以很方便的查找到此商品的购买情况,但要查找到买人的交易记录比较麻烦。 
    
    
    
    所以常见的解决方式有: 
    
         a.通过扫表的方式解决,此方法基本不可能,效率太低了。 
    
         b.记录两份数据,一份按照用户纬度分表,一份按照商品维度分表。 
    
         c.通过搜索引擎解决,但如果实时性要求很高,又得关系到实时搜索。 
    
    
    
    2.   联合查询的问题 
    
    联合查询基本不可能,因为关联的表有可能不在同一数据库中。 
    
    
    
    3.   避免跨库事务 
    
    避免在一个事务中修改db0中的表的时候同时修改db1中的表,一个是操作起来更复杂,效率也会有一定影响。 
    
    
    
    4.   尽量把同一组数据放到同一DB服务器上 
    
    例如将卖家a的商品和交易信息都放到db0中,当db1挂了的时候,卖家a相关的东西可以正常使用。也就是说避免数据库中的数据依赖另一数据库中的数据。 
    
    一主多备 
    
    在实际的应用中,绝大部分情况都是读远大于写。Mysql提供了读写分离的机制,所有的写操作都必须对应到Master,读操作可以在Master和Slave机器上进行,Slave与Master的结构完全一样,一个Master可以有多个Slave,甚至Slave下还可以挂Slave,通过此方式可以有效的提高DB集群的QPS.                                                       
    
    所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。 
    
    此外,可以看出Master是集群的瓶颈,当写操作过多,会严重影响到Master的稳定性,如果Master挂掉,整个集群都将不能正常工作。 
    
    所以,1. 当读压力很大的时候,可以考虑添加Slave机器的分式解决,但是当Slave机器达到一定的数量就得考虑分库了。 2. 当写压力很大的时候,就必须得进行分库操作。 
    
    --------------------------------------------- 
    
    MySQL使用为什么要分库分表 
    可以用说用到MySQL的地方,只要数据量一大, 马上就会遇到一个问题,要分库分表. 
    这里引用一个问题为什么要分库分表呢?MySQL处理不了大的表吗? 
    其实是可以处理的大表的.我所经历的项目中单表物理上文件大小在80G多,单表记录数在5亿以上,而且这个表 
    属于一个非常核用的表:朋友关系表. 
    
    但这种方式可以说不是一个最佳方式. 因为面临文件系统如Ext3文件系统对大于大文件处理上也有许多问题.
    这个层面可以用xfs文件系统进行替换.但MySQL单表太大后有一个问题是不好解决: 表结构调整相关的操作基 
    本不在可能.所以大项在使用中都会面监着分库分表的应用. 
    
    从Innodb本身来讲数据文件的Btree上只有两个锁, 叶子节点锁和子节点锁,可以想而知道,当发生页拆分或是添加 
    新叶时都会造成表里不能写入数据. 
    所以分库分表还就是一个比较好的选择了. 
    
    那么分库分表多少合适呢? 
    经测试在单表1000万条记录一下,写入读取性能是比较好的. 这样在留点buffer,那么单表全是数据字型的保持在 
    800万条记录以下, 有字符型的单表保持在500万以下. 
    
    如果按 100库100表来规划,如用户业务: 
    500万*100*100 = 50000000万 = 5000亿记录. 
    
    心里有一个数了,按业务做规划还是比较容易的.
    View Code

    那么分库分表多少合适呢? 

    在单表1000万条记录一下,写入读取性能是比较好的. 所以在800万条记录以下, 有字符型的单表保持在500万以下分库分表

    分区分表的工作原理及使用场景和优缺点
    分区:  
    对于用户而言,分区表时一个独立的逻辑表,单底层的mysql将其分成了多个物理子表,这对于用户来说是透明的,每一个分区都会使用一个独立的表文件
    mysql
    /|
    / |
    1 2 3
    创建表的时候使用parttition by 子句定义每个分区存储的数据(某字段),执行查询的时候,优化器会根据分区定义过滤那些没有我们需要数据的分区,这样的查询只需要查询所有数据在分区即可
    分区的主要目的是将数据按照一个较粗的粒度分在不同的表中,这样可以将相关数据放在一起,如果想一次删除整个分区的数据也很方便

    详情
    适用场景:
    表非常大无法全部存在内存,或者只在表的最后有热点数据,其他的都是历史数据
    分区表的数据更容易维护,可以对独立的分区进行独立的操作
    分区表的数据可以分布在不同的机器上,从而高效使用资源
    可以使用分区表来避免某些特殊的瓶颈
    可以备份和恢复独立的分区
    缺点:
    1、一个表最多只能有1024个分区
    2、2.5.1版本中,分区表表达式必须是整数。5.5可以使用列分区
    3、分区字段中如果有主键和唯一索引列,那么主键列和唯一列都必须包含进来
    限制:
    分区表中无法使用外键约束
    需要对现有表结构进行更改
    所有分区都必须使用相同的存储引擎
    分区函数中可以使用的函数和表达式会有一些限制
    某些迎亲不支持分区(myisam和innodb是支持的)
    对于myisam分区表,不能使用load index into cache
    对于myisam表,使用分区表时需要打开更多的文件描述符

    分区类型:4种

    建表时创建分区

    Range分区:是对一个连续性的行值码范围进行分区如id<100; 100<id<200

     CREATE TABLE IF NOT EXISTS `order_range` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户id',
      `store_id` int(10) unsigned NOT NULL COMMENT '商店id',
      `customer_surname` varchar(30) NOT NULL ,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='xx表' AUTO_INCREMENT=1 partition by range(id)(
        partition p0 values less than(5), 
        partition p1 values less than(10), 
        partition p2 values less than(15)
    );
    #将用户表分成4个分区,以每300万条记录为界限,每个分区都有自己独立的数据、索引文件的存放目录,
    #与此同时,这些目录所在的物理磁盘分区可能也都是完全独立的,可以提高磁盘IO吞吐量
    CREATE TABLE users (
           uid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
           name VARCHAR(30) NOT NULL DEFAULT '',
           email VARCHAR(30) NOT NULL DEFAULT ''
    )
    PARTITION BY RANGE (uid) (
           PARTITION p0 VALUES LESS THAN (3000000)
           DATA DIRECTORY = '/data0/data'
           INDEX DIRECTORY = '/data1/idx',
     
           PARTITION p1 VALUES LESS THAN (6000000)
           DATA DIRECTORY = '/data2/data'
           INDEX DIRECTORY = '/data3/idx',
     
           PARTITION p2 VALUES LESS THAN (9000000)
           DATA DIRECTORY = '/data4/data'
           INDEX DIRECTORY = '/data5/idx',
     
           PARTITION p3 VALUES LESS THAN MAXVALUE     DATA DIRECTORY = '/data6/data' 
           INDEX DIRECTORY = '/data7/idx'
    );
    View Code

    修改:

    List分区:   跟Range分区类似,不过他存放的是一个离散值的集合

     CREATE TABLE IF NOT EXISTS `order_range` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `store_id` int(10) unsigned NOT NULL COMMENT '商店id',
      `customer_surname` varchar(30) NOT NULL ,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='xx表' AUTO_INCREMENT=1 partition by range(id)(
        PARTITION pNorth VALUES IN (3,5,6,9,17),      //北区
        PARTITION pEast VALUES IN (1,2,10,11,19,20),  //东区
        PARTITION pWest VALUES IN (4,12,13,14,18),    //西区
        PARTITION pCentral VALUES IN (7,8,15,16)      //中心区
    );
    //20个音像店,分布在4个有经销权的地区
    这使得在表中增加或删除指定地区的雇员记录变得容易起来。例如,假定西区的所有音像店都卖给了其他公司。那么与在西区音像店工作雇员相关的所有记录(行)可以使用查询“ALTER TABLE employees DROP PARTITION pWest;”来进行删除,它与具有同样作用的DELETE (删除)查询“DELETE query DELETE FROM employees WHERE store_id IN (4,12,13,14,18);”比起来,要有效得多
    View Code
    #分成4个区,数据文件和索引文件单独存放。
    CREATE TABLE category (
         cid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
         name VARCHAR(30) NOT NULL DEFAULT ''
    )
    PARTITION BY LIST (cid) (
         PARTITION p0 VALUES IN (0,4,8,12)
         DATA DIRECTORY = '/data0/data' 
         INDEX DIRECTORY = '/data1/idx',
         
         PARTITION p1 VALUES IN (1,5,9,13)
         DATA DIRECTORY = '/data2/data'
         INDEX DIRECTORY = '/data3/idx',
         
         PARTITION p2 VALUES IN (2,6,10,14)
         DATA DIRECTORY = '/data4/data'
         INDEX DIRECTORY = '/data5/idx',
         
         PARTITION p3 VALUES IN (3,7,11,15)
         DATA DIRECTORY = '/data6/data'
         INDEX DIRECTORY = '/data7/idx'
    );  
    View Code

    Hash分区:对用户定义的表达式所返回的值来进行分区,可以写成Partitions(分区数目),或者直接使用分区语句比如:partition p0 values in...HASH分区主要用来确保数据在预先确定数目的分区中平均分布。在RANGE和LIST分区中,必须明确指定一个给定的列值或列值集合应该保存在哪个分区中;而在HASH分区中,MySQL 自动完成这些工作,你所要做的只是基于将要被哈希的列值指定一个列值或表达式,以及指定被分区的表将要被分割成的分区数量

    这中模式允许DBA通过对表的一个或多个列的Hash Key进行计算,最后通过这个Hash码不同数值对应的数据区域进行分区,。例如DBA可以建立一个对表主键进行分区的表

    例如,下面的语句创建了一个使用基于“store_id”列进行 哈希处理的表,该表被分成了4个分区:
    
    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,
        store_id INT
    )
    PARTITION BY HASH(store_id)
    PARTITIONS 4
    #分成4个区,数据文件和索引文件单独存放
    CREATE TABLE users (
         uid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
         name VARCHAR(30) NOT NULL DEFAULT '',
         email VARCHAR(30) NOT NULL DEFAULT ''
    )
    PARTITION BY HASH (uid) PARTITIONS 4 (
         PARTITION p0
         DATA DIRECTORY = '/data0/data'
         INDEX DIRECTORY = '/data1/idx',
     
         PARTITION p1
         DATA DIRECTORY = '/data2/data'
         INDEX DIRECTORY = '/data3/idx',
     
         PARTITION p2
         DATA DIRECTORY = '/data4/data'
         INDEX DIRECTORY = '/data5/idx',
     
         PARTITION p3
         DATA DIRECTORY = '/data6/data'
         INDEX DIRECTORY = '/data7/idx'
    );
    View Code

    Key分区:与Hash分区类似只不过分区支持一列或者多列,并且MYSQL服务器自身提供hash函数

    CREATE TABLE users (
         uid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
         name VARCHAR(30) NOT NULL DEFAULT '',
         email VARCHAR(30) NOT NULL DEFAULT ''
    )
    PARTITION BY KEY (uid) PARTITIONS 4 (
         PARTITION p0
         DATA DIRECTORY = '/data0/data'
         INDEX DIRECTORY = '/data1/idx',
         
         PARTITION p1
         DATA DIRECTORY = '/data2/data' 
         INDEX DIRECTORY = '/data3/idx',
         
         PARTITION p2 
         DATA DIRECTORY = '/data4/data'
         INDEX DIRECTORY = '/data5/idx',
         
         PARTITION p3 
         DATA DIRECTORY = '/data6/data'
         INDEX DIRECTORY = '/data7/idx'
    );

    在创建好表的情况下添加分区

    alter table order_range add partition(
        partition p4 less than(20),
        partition p5 less than MAXVALUE
    );

    查看建表结构:

    show create table 你的表名;

    查看是否支持分区

    SHOW VARIABLES LIKE '%partition%';

    表的各种参数状态

    show table status;

    查看分区情况:

    select
    partition_name part,
    partition_expression expr,
    partition_description descr,
    table_rows
    from information_schema.partitions where
    table_schema = schema()
    and table_name='填入你要查看的表名';
    View Code

    通过数据字典查看分区信息

    select * from information_schema.partitions;

    通过此语句扫描分区及其使用情况

    explain partitions select * from mdl_user;

    更多详细MySQL分区(Partition)功能

    注意:

    MYSQL的分区字段,必须包含在主键字段内(即必须申明primary key)
    MySQL 把NULL视为0。如果你希望回避这种做法,你应该在设计表时不允许空值;最可能的方法是,通过声明列“NOT NULL”来实现这一点


    分库分表

    表的行数超过500万行或者单表容量超过10GB时,查询就会变慢
    通过一些hash算法或者工具实现将一张数据表垂直或者水平进行物理切分
    分表方式:水平分割 垂直分割
    水平分割(类似word分页 表的结构一样):mysql 水平分表技术

    表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询速度
    使用场景:
    表中的数据本身就有独立性,例如表中分别记录哥哥地区的数据或者不同时期的数据,特别是有些数据常用,有些不常用

    用户表可以根据用户的手机号段进行分割如user183、user150、user153、user189等,每个号段就是一张表
    用户表也可以根据用户的id进行分割,加入分3张表user0,user1,user2,如果用户的id%3=0就查询user0表,如果用户的id%3=1就查询user1表
    对于订单表可以按照订单的时间进行分表

    需要把数据存放在多个介质上(最新数据做缓存或者放在不同的服务器上)

    大表统计:新建一个表进行统计

    创建一个中间表,中间表的结构和原始表结构一样,或多字段,将原始表中的部分数据转移到中间表,然后对中间表进行统计。
    中间表复制源表部分数据,并且与源表相隔离,在中间表上做统计查询不会对在线应用产生负面影响
    中间表上可以灵活的添加索引增加临时用的新字段,从而达到提高统计查询效率和辅助统计查询作用

    水平分割缺点:
    给应用增加了复杂度,通常查询需要多个表名,查询所有数据都需要union操作
    在许多数据库应用中,这种复杂性会草果他带来的优点,查询时会增加读一个索引层的磁盘次数

    垂直分表
    把主键和一些列放在一个表,主键和另外一些不常用的列放在另外一张表;

    如:用户表拆分为user_info(id,userid,name,pwd,status)和user_base(id,userid,name,age,tel,adr,sex)
    应用场景:
    1、如果一个表中某些列常用,另外一些不常用
    2、可以使数据行变小,一个数据页能存储更多的数据。查询时减少I/O次数
    垂直分表缺点:管理冗余,查询所有的数据需要join操作

    分库分表缺点:
    有些分表的策略基于应用层的逻辑算法,一旦逻辑算法改变,整个分表的逻辑都会改变,扩展性较差
    对于用用层来说,逻辑算法无疑增加开发成本

    MySQL的主从复制及负载原理:
    主从复制原理
    在主库上把数据更改记录到二进制日志
    从库将主库的日志复制到自己的中继日志
    从库读取中继日志中的事件,将其重放到从库的数据中
    主从复制解决的问题:
    数据分布:随意停止或开始复制,并在不同的地理位置分布数据备份

    负载均衡
    1、降低单个服务器压力
    2、高可用和故障切换,帮助应用程序避免单点失败
    升级测试:可以使用更高的版本的mysql作为从库

    使用mycat中间件进行分库分表


    mysql的安全性方案
    1、使用预处理语句防止sql注入
    如果从客户端传过来?id=1 or 1=1那么sql为
    delete from user where id=1 or 1=1 将会删除所用的user数据
    2、写入数据库的数据要进行特殊字符的转义
    3、查询错误信息不要返回给用户,将错误写入日志

    myqsl的其他阿安全设置
    定期做数据备份
    不给查询用户的root权限,合理分配权限
    关闭远程访问数据库的权限
    修改root口令,不用默认的口令,使用较复杂的口令
    删除多余的用户
    改变root用户的名称
    限制一般用户浏览其他库
    限制用户对数据文件的访问权限

    从句顺序:
    select---form---where---group by---having---order by---limit
    where 条件后跟的操作符:
    算术运算符:+ - * /
    比较运算符:> < = >= <= !=或者<>
    逻辑运算符: and or
    其他运算符:
    in(value1,value2,...) where id in(1,3,4)相当于where id=1 or id=3 or id=4;
    between(value1,value2) where id between 1 and 10;相当于where id >=1 and id <= 10;
    not 否定后面的条件 where id not between 1 and 10;相当于 where id>10;
    is null
    is not nul
    like '查询的字符'; 模糊查询
    %通配符 任意长度的字符串包括空字符串 %值 以值结尾 值% 以值开始 %值% 包含该值
    select * from user where name like %尹莉%;
    _通配符 代表任意一个字符

    拼接字符串: select concat(path.'_','id');
    统计:
    count(filed)统计非 null的个数
    min(filed) 最小值
    max(filed) 最大值
    sum(filed) 求和
    avg(filed) 平均数

    取值范围 2*(字节数-1)次方
    整数类型:
    tinyint
    smallint
    mediumint
    int
    bigint
    浮点:
    float(M,D)
    double(M,D)
    定点:
    decimal(M,D)
    M:代表总有效位数,不包括小数点
    D:小数部分的位数

    字符串类型:
    cahr(M) 定长、会删除尾部的空格
    varchar(M) 变长、会保留尾部的空格
    tinytext <= 512
    text < 2^16
    longtext < 2^32
    mediumtext
    二进制对象型,blob
    tinyblob
    blob
    mediumblob
    longblob

    枚举型:
    enum("A","B") 必须引号包起来 可以定义65535个数据项

    集合类型:
    set("A","B","C",...) 最多可以定义64个数据项
    日期型:
    Date: 显示格式:YYYY-MM-DD
    time, 显示格式:HH:MM:SS
    datetime 显示格式:YYYY-MM-DD HH:MM:SS
    year 显示格式:YYYY
    timestamp

    约束条件:
    null 默认
    not null
    default 默认插入值
    zerofill 零填充
    unsigned 无符号
    auto_increment 自增 一般主键才用 字段加上这个后,后面必须跟primary key或者unique

    索引
    1、常规索引: index
    在创建表的时候创建索引:

    create table table_name(
        id int(11) unsigned not null auto_increment,
        name char(32),
        age int(11) unsigned,
        index 索引名(name) //给name字段添加索引
    ) ENGINE=innoDB DEFAULT CHARSET=utf8;

    创建完表以后创建索引:
    create index 索引名 on 表名(字段名);
    create index now_age on user(age);
    删除索引: drop index 索引名 on table_name;
    2、唯一索引:unique key

    create table table_name(
        id int(11) unsigned not null auto_increment,
        name char(32),
        age int(11) unsigned,
        unique 索引名(name) //给name字段添加索引
    ) ENGINE=innoDB DEFAULT CHARSET=utf8;

    创建完表以后创建索引:
    create unique 索引名 on 表名(字段名);
    create unique now_age on user(age);

    删除索引: drop unique 索引名 on table_name;
    外键 foreign key 外键只有innodb类型的存储引擎支持
    3、主键索引: primary key
    删除主键索引一般要两个步骤:
    检查有没有auto_increment,有的话先删掉auto_increment再删掉primary key
    alter table table_name drop primary key
    drop foreign key;
    4、全文索引:Fulltext
    5、组合(复合)索引:将多个列组合在一起创建索引

    主键索引和唯一索引的区别:
    一个表只有一个主键索引,可以有多个唯一索引
    主键索引一定是唯一索引,唯一索引不是主键索引
    主键可以与外键构造参照完整性约束,防止数据不一致
    创建表直接制定索引 INDEX [indexName] (fieldname)

    CREATE TABLE `user` ( 
        `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, 
        `name` char(80) NOT NULL DEFAULT '', 
        `classid` int(20) NOT NULL DEFAULT '', 
        `aihao` set('2','4','3','1') NOT NULL DEFAULT '4,1' COMMENT '集合型',
        `sex` enum('girl','boy') NOT NULL DEFAULT 'boy' COMMENT '枚举型',
        PRIMARY KEY (`id`), 主键索引
        constraint `myclassid` foreign key(`classid`) references `class_info` (`id`),
        UNIQUE KEY `name` (`name`), 唯一索引
        KEY `myclassid` ('classid') index普通索引
        KEY `test` ('classid ','sex','aihao') 复合普通索引
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

    注意事项

    Myisam(8.0要废弃了):数据操作快速的一种引擎,不支持事务处理功能,支持全文检索。文件保存在数据库名称为目录名的目录中,有3个文件。 5.1- 默认MyISAM。支持全文索引压缩空间函数。不支持事物和行级锁,不支持崩溃后的安全恢复
    Innodb:功能强大的一种引擎,支持事务处理功能,不支持全文检索。文件保存在两个地方,一个是在数据库名称为目录名的目录中存放表结构文件,它的数据是保存在一个共有的文件中的,可以通过配置分开。对主键的查询性能高于其他类型的存储引擎。内部做了很多优化从磁盘读取数据时自动在内存构建hash索引。出啊如数据时自动构建插入缓冲区。通过一些机制和工具支持真正的热备份。支持崩溃后的安全恢复。支持行级锁。支持外键

    共享锁(读锁) 排他锁(写锁)
    锁粒度表锁(这会阻塞其他用户对该表的所有读写操作 只在排他锁时生效) 行锁(这会阻塞其他用户对该表正在写入行的读写操作 只在排他锁时生效)

    存储过程:为以后的使用而保存的一条或多条mysql语句的集合。存储过程就是有业务逻辑业务流程的集合,可以在存储过程中创建表、更新数据、删除等等
    场景:通过把处理封装在容易使用的单元中,简化复杂的操作,保证数据的一致性

    触发器:提供给程序员和数据分析员来保证数据完整性的一种方法,他是与表事件相关的特殊的存储过程
    使用场景:可以通过数据库中的相关表实现级联更改,实时监控某张表中的某个字段的更改而需要作出相应的处理。某些业务编号的生成。滥用会造成数据库及应用程序的维护困难

    特点

    MyISAM InnoDB Memory MERGE NDB
    存储限制 有 64TB 有 没有 有
    事务安全 支持
    锁机制 表锁 行锁 表锁 表锁 行锁
    B树索引 支持 支持 支持 支持 支持
    哈希索引 支持 支持
    全文索引 支持
    集群索引 支持
    数据缓存 支持 支持 支持
    索引缓存 支持 支持 支持 支持 支持
    数据可压缩 支持
    空间使用 低 高 N/A 低 低
    内存使用 低 高 中等 低 高
    批量插入的速度 高 低 高 高 高
    支持外键 支持

    +--------------------------+--------------------------------+
    | Variable_name | Value |
    +--------------------------+--------------------------------+
    | character_set_client | utf8mb4 |客户端设置
    | character_set_connection | utf8mb4 |客户端设置
    | character_set_database | latin1 |这个是当前所在的数据库字符集;默认的是latin1字符集
    | character_set_filesystem | binary |
    | character_set_results | utf8mb4 |客户端设置
    | character_set_server | utf8mb4 |
    | character_set_system | utf8 |character_set_system是个只读数据不能更改
    | character_sets_dir | D:xamppmysqlsharecharsets |
    +--------------------------+--------------------------------+
    character_set_client、character_set_connection、character_set_results 是客户端连接mysql时选择的字符集,然后服务器就会去设置这三个的值
    如果我们想告诉mysql server自己本次连接想使用latin1,则命令行下可以如下写法:
    mysql -uroot -h 192.168.2.11 -pAbcd@1234 --default-character-set=latin1
    临时更改字符集:
    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;
    永久更改默认字符集:
    从my.ini下手(标签下没有的添加,有的修改)
    [client]
    default-character-set=utf8
    [mysql]
    default-character-set=utf8
    [mysqld]
    default-character-set=utf8


    修改服务器级别的字符集:
    临时修改:set global character_set_server=utf8;
    永久修改: my.ini、my.conf 在[mysqld]后加上character_set_server=utf8

    flush 语法

    FLUSH [LOCAL | NO_WRITE_TO_BINLOG] flush_option [, flush_option] ...

    flush_option 包含:
    flush
    logs : 刷新二进制日志文件 flush PRIVILEGES:刷新权限,修改权限或密码后,需要使用到该命令 flush tables:关闭所有表,并清空缓存中的类容 。 flush tables with read lock:关闭所有打开的表,并且对所有DB中的表添加一个读锁, 直到显示执行unlock tables 。该命令常用语备份数据。 flush master :删除所有二进制日志索引文件中的二进制日志文件,重置二进制日志文件的索引文件为空, 创建一个新的二进制日志文件,早起版本支持 ,现版本中使用reset master 替代。 和purge的基本一样。 区别:purege 仅仅清空二进制日志文件 reset master 清空二进制日志并且重置二进制日志索引文件 flush status :重置大多数状态变量到0 只在当调试查询时,您才应该使用此项 flush Query Cache:重整查询缓存,消除其中的碎片,***能,但并不影响查询缓存中的现有数据

    常见数据库常用数据类型、默认端口

  • 相关阅读:
    csharp customer style print
    C++各大有名库的介绍
    关联,依赖,泛化(又称继承分为扩展或包含),实现,聚合(共享),复合(组合)
    有关数据库设计经验简介
    Msxml2.XMLHTTP Microsoft.XMLHTTP new XMLHttpRequest
    用例图
    设计模式之抽象工厂模式
    银行软件业务开发分类杂谈多年前的旧文
    #ifndef、#def、#endif说明
    C#.NET向现有文件添加文本+创建一个新文本文件并写入一个字符串
  • 原文地址:https://www.cnblogs.com/lichihua/p/9302652.html
Copyright © 2011-2022 走看看