mysql高级优化

mysql优化大的思路:
查看状态:

mysql> show status;

Queries | 3

Threads_connected | 1

Threads_running | 1

[root@localhost ~]# mysql -S /tmp/mysql3306.sock -e “show processlist\G”|grep State:|sort|uniq -c|sort -rn

以下几种状态要注意:

converting HEAP to Myisam 查询结构太大,把结果放在磁盘

create tmp table 创建临时表(如group时储存中间结果)

Copying to tmp table on disk 把内存临时表复制到磁盘

locked 被其他查询锁住

logging slow query 记录慢查询

查看size大小

mysql> show variables like ‘%size%’;

其中

tmp_table_size | 268435456 为

设置为1024

mysql> set global tmp_table_size=1024;

设置本次会话生效:

mysql> set session tmp_table_size=1024;

打开mysql自带性能分析

mysql> show variables like ‘%profiling%’;

开始跑测试数据:

mysql> select * from customer where c_id<10000;

查看结果:

mysql> show profiles;

±---------±-----------±----------------------------------------+

| Query_ID | Duration | Query |

±---------±-----------±----------------------------------------+

| 1 | 0.00296500 | show variables like ‘%profiling%’ |

| 2 | 0.00039850 | show tables |

| 3 | 0.00053700 | select * from customer limit 10 |

| 4 | 3.23267150 | select * from customer where c_id<10000 |

±---------±-----------±----------------------------------------+

4 rows in set, 1 warning (0.00 sec)

mysql> show profile for query 4;

±---------------------±---------+

| Status | Duration |

±---------------------±---------+

| starting | 0.000514 |

| checking permissions | 0.000016 |

| Opening tables | 0.000016 |

| init | 0.000080 |

| System lock | 0.000014 |

| optimizing | 0.000057 |

| statistics | 0.000020 |

| preparing | 0.000013 |

| executing | 0.000003 |

| Sending data | 3.231762 |

| end | 0.000013 |

| query end | 0.000007 |

| closing tables | 0.000008 |

| freeing items | 0.000103 |

| logging slow query | 0.000036 |

| cleaning up | 0.000011 |

±---------------------±---------+

16 rows in set, 1 warning (0.00 sec)

索引优化策略:

  1. 索引类型:

B-tree索引
注:名叫b-tree索引,大的方面看,都用的平衡树,但具体的实现上,各引擎稍有不同,比如,严格的说,NBD引擎,使用的是T-tree。
myisam,innodb默认使用B-tree索引,B-tree可理解为“排好序的快速查找结构”

hash索引:
在memory表里,默认是hash索引,hash的理论查询时间复杂度为O(1)

疑问:既然hash的查找如此高效,为什么不都用hash索引?

1.hash函数计算后的结果,是随机的,如果是在磁盘上放置数据,比如主键ID为例,那么随着id的增长,id对应的行,在磁盘上随机放置,
2.无法对范围查询进行优化
3.无法利用前缀索引,比如在b-tree中,field列的值 helloworld,并加索引查询xx=helloworld 自然可以利用索引,xx=hello,也可以利用索引,(左前缀索引)因为hash(‘helloworld’)和hash(‘hello’),两者的关系仍为随机
4.排序也无法优化
5.必须回行,就是说 通过索引拿到数据位置,必须回到表中取数据。

一、B-tree索引的常见误区

1、在where条件常用的列上都加上列索引
例:where cat_id=3 and price>100; 查询第三个栏目,100元以上的商品
误:cat_id上和price 上都加上索引
错:只能用上cat_id或price索引,因为是独立的索引,同时只能用上1个

二、在多列上建立索引后,查询哪个列,索引都将发挥作用
误:多列索引上,索引发挥作用,需要满足左前缀要求。
以index(a,b,c)为例
语句 索引是否发挥作用
where a=3 是
where a=3 and b=5 是
where a=3 and b=5 and c=4 是
where b=3 或 where c=4 否
where a=3 and c=4 a列能发挥索引,c不能
where a=3 and b>10 and c=7 a能利用索引,b能利用,c不能利用
同上 where a=3 and b like ‘xxxx%’ and c=7 a能利用索引,b能利用索引,c不能用

索引问题:

假设某个表有一个联合索引(c1,c2,c3,c4)
where c1=x and c2=x and c4>x and c3=x
答案:全部用上了,虽然看起来规则颠倒,但是mysql自身会进行sql语句优化。不改变本意的情况下

where c1=x and c2=x and c4=x order by c3

where c1=x and c4=x order by c3,c2

where c1=?and c5=? order by c2,c3

where c1=? and c2=? and c5=? order by c2,c3

接下来我建表来帮你解答一下哈定义表t,有c1到c5 5个字段,特别说明一下 字段类型都是定长char(1)类型,并且非空,字符集是utf8(与计算索引使用字节数有关)
QQ截图20131109233034.png

创建联合索引
QQ截图20131109234601.png

插入2条测试数据
QQ截图20131109234733.png

好,我们先来看A选项
QQ截图20131109234954.png

我们看解析A这条sql的结果,与索引有关的主要是possible_keys,key,key_len这三项,
possible_keys是指可能会用到的索引,key是当前sql使用到的索引,key_len是索引的使用字节数
key的值是c1234表示联合索引用上了,那是不是c1,c2,c3,c4全用上了咧,我们得从key_len分析一下
因为字段类型是char(1),字符集是utf8,所以每个字段的key_len 是 1*3=3,key_len现在等于12表示c1,c2,c3,c4这四个字段都用上了索引,(如果字段类型是null,那单个字段的索引字节数需要 +1,如果字段类型为非定长类型,比如varchar,那字节数需要再 +2,这里方便理解,统一定义成了定长char)

再接着看B这条sql语句
QQ截图20131110000049.png

我们看到key=c1234,表示B使用了联合索引,key_len=6表示有两个字段使用了索引,这两个字段就是C1和c2,这个sql里面有一个order by c3,order by不能使用索引,但是却利用了索引,为什么这么说咧,先看C这条sql
QQ截图20131110000731.png

key=c1234,表示B使用了联合索引,key_len=3表示有1个字段使用了索引,这个字段就是C1,与B语句不一样的是 Extra的值
C语句里面使用了临时表(Using temporary) 和 排序(filesort),
因为组合索引是需要按顺序执行的,比如c1234组合索引,要想在c2上使用索引,必须先在c1上使用索引,要想在c3上使用索引,必须先在c2上使用索引,依此。。
回到B语句中,因为c2字段已经使用了索引,所以在order by c3的时候 c3其实在索引表里面已经是排好序的了,不需要建临时表,不需要再排序,所以说其实他利用上了索引
而C语句中,group by 的顺序是先c3,再c2,在对c3进行group by的时候,c2字段上的索引并没用使用,所以索引在这里就断了,只用上了c1一个字段的索引

D语句c1字段使用了索引,c2,c3字段在order by中是顺序执行 所以也利用了索引

QQ截图20131110002133.png

E语句c1和c2使用了索引,c3在order by中利用了索引
QQ截图20131110002358.png

计算平均值sql:

select cat_id,avg(shop_price) from ecs_goods group by cat_id;

清理缓存sql:

mysql> reset query cache;

索引类型:

聚簇索引

索引覆盖

一、聚簇索引区别

innodb与myisam区别

innodb的次索引指向对主键的引用(数据聚簇在一起)

myisam的次索引和主索引都指向磁盘物理行(数据文件)

innodb的主索引文件上 直接存放该行数据,称为聚簇索引,次索引指向对主键的引用
myisam中,主索引和次索引,都指向对物理行

注意:innodb来说:
1:主键索引,即存储索引值,又在叶子中存储行的数据
2:如果没有主键,则会unique key做主键
3:如果没有unique,则系统生成一个内部的rowid做主键
4:像innodb中,主键的索引结构中,即存储了主键值,又存储了行数据,这种结构称为”聚簇索引“

二、覆盖索引:
永远记住查索引是快的,回行是慢的(从磁盘上返回数据)

索引覆盖是指 如果查询的列恰好是索引的一部分,那么查询只需要在索引文件上进行,不需要回行到磁盘再找数据。
这种查询速度非常快,

explain xxxx
如果最后又 using index 说明使用了索引覆盖,速度是非常快的

问题案例:
create table A (
id varchar(64) primary key,
ver int,
)

在id、ver上有联合索引
100000条数据

为什么select id from A order by id 特别慢?
而select id from A order by id,ver非常快
我的表有几个很长的字段varbinary(3000)

分析:
1.是innodb引擎
2.有多个比较长的列
3.是聚簇索引,导致沿id排序时,要跨好多小文件块
4.有比较长的列,导入块比较多

1.如果是myisam,将不存在这个问题

高性能索引策略:
对于innodb而言,因为节点下有数据文件,因此节点的分裂将会比较慢,
对于innodb的主键,尽量用整型,而且是递增的整型,如果是无规律的数据,将会产生的页的分裂,影响速度。

好的索引:
1.查询频繁 2.区分度高 3.长度小 4.尽量能覆盖常用查询字段

取出最长字节的数据:

mysql> select dept_no,dept_name from departments order by length(dept_name) desc limit 2;

±--------±-------------------+

| dept_no | dept_name |

±--------±-------------------+

| d006 | Quality Management |

| d009 | Customer Service |

±--------±-------------------+

索引优化总结:
1.首先分析表是聚簇索引还是非聚簇索引,
2.是innodb还是myisam,
3.能不能索引覆盖,
4.常查询的列是不是经常在一起查的,可以建联合索引
5.索引的长度要建多少?怎么跟区分度保持平衡。
6.伪hash索引降低索引长度

对于左前缀不易区分的列,建立索引技巧
如URL列:
http://www.baidu.com

http://www.zixue.it

列的前11字符都是一样的,不易区分,可以用如下2个办法来解决,
1.把列的内容倒过来存储,并建立索引
moc.udiab.www//:ptth
ti.euxiz.www://ptth
这样左前缀区分度大

2.伪hash索引效果
同时存url_hash列

实验:
创建测试表:

mysql> create table t10 (

 id int primary key auto_increment,

 url varchar(30) not null default ''

 )

 ;

Query OK, 0 rows affected (0.03 sec)

插入url数据:

mysql> insert into t10 (url) values (‘www.baidu.com’),(‘www,zixue.it’);

Query OK, 2 rows affected (0.01 sec)

Records: 2 Duplicates: 0 Warnings: 0

查看是否支持crc模式:

mysql> select crc32(‘a’);

±-----------+

| crc32(‘a’) |

±-----------+

| 3904355907 |

±-----------+

1 row in set (0.00 sec)

增加一个列,并且指定crcurl是无符号

mysql> alter table t10 add crcurl int unsigned not null default 0;

Query OK, 0 rows affected (0.05 sec)

Records: 0 Duplicates: 0 Warnings: 0

mysql> select * from t10;

±—±--------------±-------+

| id | url | crcurl |

±—±--------------±-------+

| 1 | www.baidu.com | 0 |

| 2 | www,zixue.it | 0 |

±—±--------------±-------+

设定crcurl列数据为url列数据转化

mysql> update t10 set crcurl=crc32(url);

Query OK, 2 rows affected (0.00 sec)

Rows matched: 2 Changed: 2 Warnings: 0

添加索引

mysql> alter table t10 add index url(url(16));

Query OK, 0 rows affected (0.02 sec)

Records: 0 Duplicates: 0 Warnings: 0

mysql> alter table t10 add index crcurl(crcurl);

Query OK, 0 rows affected (0.02 sec)

Records: 0 Duplicates: 0 Warnings: 0

按照生产业务应该先转化为crc32:

mysql> select crc32(‘www.baidu.com’);

±-----------------------+

| crc32(‘www.baidu.com’) |

±-----------------------+

| 387695885 |

±-----------------------+

1 row in set (0.01 sec)

然后进行查询:效果对比

mysql> explain select * from t10 where url=‘www.baidu.com’\G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: t10

partitions: NULL

     type: ref

possible_keys: url

      key: url

  key_len: 66

      ref: const

     rows: 1

 filtered: 100.00

    Extra: Using where

1 row in set, 1 warning (0.00 sec)

ERROR:

No query specified

mysql> explain select * from t10 where crcurl=‘387695885’\G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: t10

partitions: NULL

     type: ref

possible_keys: crcurl

      key: crcurl

  key_len: 4

      ref: const

     rows: 1

 filtered: 100.00

    Extra: NULL

1 row in set, 1 warning (0.00 sec)

————————————————————————————
大数据量下的分页效果:
select field from table limit 30,10;

比如 每页显示perpage条,当前是第N页
前面翻过了(N-1)*perpage

limit (N-1)*perpage,N

问题:面试官提问,当翻到了9999页,查询速度非常慢,效率非常低,怎么办?

1.从业务上去优化
办法:不允许翻过100页
以百度为例,一般翻页到70页左右,谷歌40页左右

问题:

mysql> select emp_no,birth_date from employees limit 100000,10 ;
为什么limit offset 的效率这么低
在offset 比较大时
答:以为是自上而下逐行查找,用limit offset 时,并不是先跳过,再查询,而是先查询,后跳过。
案例:
limit 100W/10
就要把100w取出来,然后跳过前100W行

可以改进:

mysql> select emp_no,birth_date from employees limit 300000,3 ;

±-------±-----------+

| emp_no | birth_date |

±-------±-----------+

| 499976 | 1963-08-20 |

| 499977 | 1956-06-05 |

| 499978 | 1960-03-29 |

±-------±-----------+

3 rows in set (0.06 sec)

mysql> select emp_no,birth_date from employees where emp_no>300000 limit 3;

±-------±-----------+

| emp_no | birth_date |

±-------±-----------+

| 400000 | 1963-11-29 |

| 400001 | 1962-06-02 |

| 400002 | 1964-08-16 |

±-------±-----------+

3 rows in set (0.00 sec)

1.为什么下面比上面快很多,
答:因为emp_no是建了主键索引,索引发挥了作用

缺点:要求数据完整性,没有被删除过,因为一旦删除过数据,那么根据ID顺序来取出的数据就不正常。
2.为什么两次数据不一致?
答:原因:数据被物理删除过,有空洞
解决:数据不进行物理删除(可以逻辑删除),最终在页面上显示数据时,逻辑删除的条目不显示即可
缺点:要求数据完整性,没有被删除过,因为一旦删除过数据,那么根据ID顺序来取出的数据就不正常。
(一般来说,大网站的数据都是不物理删除,只做逻辑删除(逻辑标记,比如is_delete=1))

3.非要物理删除,还要用offset精确查询,还不限制用户分页,怎么办?
分析:优化思路是 不查,少查,查索引,少取

我们现在必须要查,则只查索引,不查数据,得到id
再用id去查具体条目,这种技巧就是延迟索引
select lx_com.id,name from lx_com inner join (select id from lx_com limit 5000000,10) as tmp on lx_com.id=tmp.id;

mysql> select id,name from lx_com inner join (select id from lx_com limit 500000,10) as tmp using(id);

索引与排序:

排序可能发生2种情况:
1.对于覆盖索引,直接在索引上查询时,就是有顺序的,using index
2.先取出数据,形成临时表做filesort(文件排序,但文件可能在磁盘上,也可能在内存中)

我们的争取目标-----取出来的数据本身就是有序的,利用索引来排序

比如:goods商品表,(cat_id,shop_price)组成联合索引,
where cat_id=N order by shop_price,可以利用索引来排序

可以:
select goods_id,cat_id,shop_price from goods order by shop_price;
//using where,按照shop_price索引取出的结果,本身就是有序的。

不可以:
select goods_id,cat_id,shop_price from goods order by click_count;
//using filesort 用到了文件排序,即取出的结果再次排序。

重复索引与冗余索引
重复索引:是指 在同一个列(如age),或者 顺序相同的几个列(age,school),建立多个索引
称为重复索引,重复索引没有任何帮助,只会增大索引文件,拖慢更新速度,去掉

冗余索引;

冗余索引是指2个索引所覆盖的列有重叠,称为冗余索引
比如x,m列,加索引 index x(x),index xm(x,m)

x,m索引,两者的x列重叠了,这种情况下,称为冗余索引

甚至可以把index mx(m,x)索引也建立,mx,xm也不是重复的,因为列的顺序不一样

比如,冗余索引:
alter table test add index click1 (click_count);
alter table test add index click2 (click_count);

还有:
x,y ,index xy(x,y) ,index yx(y,x) 就是冗余索引

索引碎片与维护:

在长期的数据更改过程中,索引文件和数据文件,都将产生空洞,形成碎片

我们可以通过一个nop操作(不产生对数据实质影响的操作),来修改表

比如:表的引擎为innodb,可以alter table xxx engine innodb
注意:虽然没有对任何数据进行更改,但是会重新规整数据和索引文件,必须在凌晨半夜执行,非常耗时

另一种方法:
optimize table goods;

两种方法效果一样

注意:修复表的数据及索引碎片,就会把所有的数据文件重新整理一遍,使之对齐。
这个过程,如果表的行数比较大,也是非常耗费资源的操作,
所以,不能频繁的修复,

如果表的upfate操作很频繁,可以按周/月,来修复
如果不频繁,可以更长的周期来做修复

SQL语句优化:

mysql> explain select 1 \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: NULL

partitions: NULL

     type: NULL

possible_keys: NULL

      key: NULL

  key_len: NULL

      ref: NULL

     rows: NULL

 filtered: NULL

    Extra: No tables used

type:
有可能是
实际的表名: 如 select * from t1;
表的别名: 如select * from t2 as tmp;
derived :如from型子查询
null : 直接计算得结果,不用走表

possible_key : 可能用到的索引
注意:系统估计可能用的几个索引,但最终,只能用1个

key:最终用的索引
key_len:使用的索引的最大长度,越短越好,速度越快

type列:是指查询的方式,非常重要,是分析“查数据过程”的重要依据,可能的值

all:意味着从表的第1行,往后,逐行做全表扫描,运气不好扫描到最后一行

ref:连接查询时,前表与后表的引用关系,引用意思

rows:估计扫描多少行

extra:using index ,using where , using temp,using filesort ,等等。。。。。

mysql> explain select to_date from dept_emp \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: dept_emp

partitions: NULL

     type: ALL

possible_keys: NULL

      key: NULL

  key_len: NULL

      ref: NULL

     rows: 331143

 filtered: 100.00

    Extra: NULL

1 row in set, 1 warning (0.01 sec)

mysql> explain select emp_no from dept_emp \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: dept_emp

partitions: NULL

     type: index

possible_keys: NULL

      key: emp_no

  key_len: 4

      ref: NULL

     rows: 331143

 filtered: 100.00

    Extra: Using index

1 row in set, 1 warning (0.00 sec)

index: 比all性能好一点
通俗的说:all 扫描所有的数据行,相当于data_all index扫描所有的索引节点,相当于index_all

2种情况可能出现:

1.索引覆盖的查询情况下,能利用上索引,但是又必须全索引扫描

mysql> explain select emp_no from dept_emp where emp_no=100001 or emp_no+1=10159 \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: dept_emp

partitions: NULL

     type: index

possible_keys: PRIMARY,emp_no

      key: emp_no

  key_len: 4

      ref: NULL

     rows: 331143

 filtered: 100.00

    Extra: Using where; Using index

1 row in set, 1 warning (0.00 sec)

2.是利用索引来进行排序,但取出所有的节点

mysql> explain select emp_no from dept_emp order by emp_no desc \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: dept_emp

partitions: NULL

     type: index

possible_keys: NULL

      key: emp_no

  key_len: 4

      ref: NULL

     rows: 331143

 filtered: 100.00

    Extra: Using index

1 row in set, 1 warning (0.00 sec)

分析:没有加where条件,就得取所有索引节点,同时,又没有回行,只取索引节点,再排序,经过所有索引节点。

range:意思是查询时,能根据索引做范围扫描

mysql> EXPLAIN select emp_no from dept_emp where emp_no>10159 \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: dept_emp

partitions: NULL

     type: range

possible_keys: PRIMARY,emp_no

      key: PRIMARY

  key_len: 4

      ref: NULL

     rows: 165571

 filtered: 100.00

    Extra: Using where; Using index

1 row in set, 1 warning (0.01 sec)

ref 意思是指 通过索引列,可以直接引用到某些数据行

mysql> EXPLAIN select emp_no from dept_emp where emp_no=10159 \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: dept_emp

partitions: NULL

     type: ref

possible_keys: PRIMARY,emp_no

      key: PRIMARY

  key_len: 4

      ref: const

     rows: 1

 filtered: 100.00

    Extra: Using index

1 row in set, 1 warning (0.01 sec)

eq_ref 是指,通过索引列,直接饮用某1行数据,常见于连接查询中

mysql> explain select employees.emp_no,employees.first_name,employees.last_name,dept_emp.dept_no from employees inner join dept_emp on employees.emp_no = dept_emp.emp_no where employees.emp_no>499997 \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: dept_emp

partitions: NULL

     type: range

possible_keys: PRIMARY,emp_no

      key: emp_no

  key_len: 4

      ref: NULL

     rows: 2

 filtered: 100.00

    Extra: Using where; Using index

*************************** 2. row ***************************

       id: 1

select_type: SIMPLE

    table: employees

partitions: NULL

     type: eq_ref

possible_keys: PRIMARY

      key: PRIMARY

  key_len: 4

      ref: employees.dept_emp.emp_no

     rows: 1

 filtered: 100.00

    Extra: NULL

2 rows in set, 1 warning (0.00 sec)

const , system , null 这3个分别指查询优化到常量级别,甚至不需要查找时间

一般按照主键来查询时,易出现const,system
或者直接查询某个表达式,不经过表时,出现null

mysql> explain select emp_no from employees where emp_no=499997 \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: employees

partitions: NULL

     type: const

possible_keys: PRIMARY

      key: PRIMARY

  key_len: 4

      ref: const

     rows: 1

 filtered: 100.00

    Extra: Using index

1 row in set, 1 warning (0.00 sec)

几个误区:
explain 不产生查询 这是错误的,在一些复杂或者大的查询中,explain也是会产生查询。
对limit的解释 查询比较复杂
explain 即执行过程 只是优化即分析结果

mysql 5.6 确实不产生查询,只产生查询计划。还可以分析非select 语句

in型子查询陷阱

mysql> select emp_no,first_name,last_name from employees where emp_no in (select emp_no from salaries where salary=107118);

±-------±-----------±----------+

| emp_no | first_name | last_name |

±-------±-----------±----------+

| 11486 | Itzchak | Ramaiah |

| 91781 | Emran | Broomell |

| 220903 | Marlo | Domenig |

| 296691 | Yuping | Welham |

| 443206 | Marco | Oppitz |

±-------±-----------±----------+

5 rows in set (7.89 sec)

实例:

说明:并没有使用emp_no索引,type为all

mysql> explain select emp_no,first_name,last_name from employees where emp_no in (select emp_no from salaries where salary=107118) \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: employees

partitions: NULL

     type: ALL

possible_keys: PRIMARY

      key: NULL

  key_len: NULL

      ref: NULL

     rows: 299866

 filtered: 100.00

    Extra: NULL

*************************** 2. row ***************************

       id: 1

select_type: SIMPLE

    table: salaries

partitions: p01,p02,p03,p04,p05,p06,p07,p08,p09,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19

     type: ref

possible_keys: PRIMARY,emp_no

      key: PRIMARY

  key_len: 4

      ref: employees.employees.emp_no

     rows: 1

 filtered: 10.00

    Extra: Using where; FirstMatch(employees)

2 rows in set, 1 warning (0.00 sec)

手动添加效果

mysql> explain select emp_no,first_name,last_name from employees where emp_no in (11486,91781,220903,296691,443206) \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: employees

partitions: NULL

     type: range

possible_keys: PRIMARY

      key: PRIMARY

  key_len: 4

      ref: NULL

     rows: 5

 filtered: 100.00

    Extra: Using where

1 row in set, 1 warning (0.01 sec)

使用下面方法:

mysql> select employees.emp_no,first_name,last_name from employees inner join ids on employees.emp_no=ids.id;

±-------±-----------±----------+

| emp_no | first_name | last_name |

±-------±-----------±----------+

| 11486 | Itzchak | Ramaiah |

| 91781 | Emran | Broomell |

| 220903 | Marlo | Domenig |

| 296691 | Yuping | Welham |

| 443206 | Marco | Oppitz |

±-------±-----------±----------+

mysql> explain select employees.emp_no,first_name,last_name from employees inner join ids on employees.emp_no=ids.id \G;

*************************** 1. row ***************************

       id: 1

select_type: SIMPLE

    table: ids

partitions: NULL

     type: ALL

possible_keys: NULL

      key: NULL

  key_len: NULL

      ref: NULL

     rows: 5

 filtered: 100.00

    Extra: NULL

*************************** 2. row ***************************

       id: 1

select_type: SIMPLE

    table: employees

partitions: NULL

     type: eq_ref

possible_keys: PRIMARY

      key: PRIMARY

  key_len: 4

      ref: employees.ids.id

     rows: 1

 filtered: 100.00

    Extra: NULL

2 rows in set, 1 warning (0.00 sec)

exists 一定比子查询慢吗?

select c.cat_id,cat_name from category as c inner join goods as g on c.cat_id=g.cat_id group by cat_name

优化后:
select c.cat_id,cat_name from category as c inner join goods as g on c.cat_id=g.cat_id group by cat_id

count优化:
误区:
1.myisam的count()非常快
答:是比较快,但仅限于查询表的”所有行“比较快,因为myisam对行数进行了存储,一旦有条件的查询,速度就不再快了,尤其是where条件的列上没有索引

2:假如,id<100 的商家是我们内部的测试,我们想查查真是的商家有多少?
select count() from lx_com where id>=100;(1000多万行用了6.X秒)
小技巧:
select count(
) from lx_com; 快
select count() from lx_com where id<100;快
select count(
) from lx_com -select count() from lx_com where id<100; 快
select (select count(
) from lx_com) -(select count(*) from lx_com where id<100);

group by
注意:
1.分组用于统计,而不是用于筛选数据
比如:统计平均分,最高分,适合,但用于筛选重复数据,则不适合
以及用索引来避免临时表和文件排序

2.以A,B表连接为例,主要查询A表的列。
那么group by,order by 的列尽量相同,而且列应该显示声明为A 的列

union优化
注意:union all不过滤,效率提高,如非必须,请用union all
因为union去重的代价非常高,放在程序里去重

巧用变量减少查询

首先建表

mysql> create table t10 (

-> name char(10) not null default '',

-> score smallint not null default 0,

-> );

插入数据:

mysql> insert into t10 values(‘zhang’,100),(‘wang’,95),(‘li’,95),(‘zhao’,90),(‘luo’,100);

排序看一下

mysql> select * from t10 order by score desc;

±------±------+

| name | score |

±------±------+

| zhang | 100 |

| luo | 100 |

| wang | 95 |

| li | 95 |

| zhao | 90 |

±------±------+

mysq变量使用:

mysql> set @age:=20;

Query OK, 0 rows affected (0.02 sec)

mysql> select @age;

±-----+

| @age |

±-----+

| 20 |

±-----+

1 row in set (0.01 sec)

mysql> set @pres:=0,@currs:=0,@rank:=0; Query OK, 0 rows affected (0.00 sec)

mysql> select name,(@currs:=score) as score,@rank:=if(@currs<>@pres,@rank:=@rank+1,@rank) as rank,@pres:=score as prev from t10 order by score desc;

±------±------±-----±-----+

| name | score | rank | prev |

±------±------±-----±-----+

| zhang | 100 | 1 | 100 |

| luo | 100 | 1 | 100 |

| wang | 95 | 2 | 95 |

| li | 95 | 2 | 95 |

| zhao | 90 | 3 | 90 |

±------±------±-----±-----+

5 rows in set (0.00 sec)

在name列添加唯一约束索引:

mysql> alter table t10 add unique index name(name);

添加报错:

mysql> insert into t10 (name,score) values(‘li’,80);

ERROR 1062 (23000): Duplicate entry ‘li’ for key ‘name’

mysql> insert into t10 (name,score) values (‘li’,80) on duplicate key update score=score+1;

Query OK, 2 rows affected (0.01 sec)

mysql> select * from t10;

±------±------+

| name | score |

±------±------+

| li | 96 |

| luo | 100 |

| wang | 95 |

| zhang | 100 |

| zhao | 90 |

±------±------+

5 rows in set (0.00 sec)


主服务器的日志格式用哪种比较好
有statement,row,mixed 这3种,其中mixed是指前2种的混合

以insert into xxtable values(x,y,x,z) 为例
影响:1行,且为新增1行,对于其他行没有影响
这个情况,用row格式,直接复制磁盘上1行的新增变化

以update xxtable set age=21 where name=‘sss’;
这个情况一般也只是影响1行,用row也比较合适

以过年发红包,全公司的人,都涨薪100元
update xxtable set salary=salary+100;
这个语句带来的影响是针对每一行的,因此磁盘上很多row都发生了变化
此处适合statement格式日志

2种日志,各有各的高效的地方,mysql提供了mixed类型,可以根据语句的不同,而自动选择适合的日志格式


主主复制

同步冲突:
例:create table stu(
id int primary key auto_increment
)…

2台mysql地位相等,假如2个请求同时到达2台服务器
请求a节点 stu的id为1
请求b节点stu的id为1
同步----冲突

如何解决?
让1台服务器1,3,5,7,9来增长
另一台服务器2,4,6,8,来增长

一台服务器:
set global auto_increment_increment = 2
set global auto_increment_offset=1;
set session auto


./bin/mysql-proxy -P 192.168.0.199:4040 --proxy-backend-addresses=192.168.0.199:3306 --proxy-backend-addresses=192.168.0.200:3306

./bin/mysql-proxy -b 192.168.0.199:3306 -r 192.168.0.200:3306 -s /usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua


MyCat又是在Cobar基础上发展的版本,两个显著点是:   

    后端由BIO改为NIO,并发量有大幅提高
    增加了对Order By、Group By、limit等聚合功能的支持(,虽然Cobar也可以支持Order By、Group By、limit语法,但是结果没有进行聚合,只是简单返回给前端,聚合功能还是需要业务系统自己完成)。

partition分区

create table topic (

  tid int primary key auto_increment,

  title varchar(20) not null default ''

  ) 

  partition by range(tid) (

  partition t0 values less than(10),

  partition t1 values less than(20),

  partition t2 values less than(MAXVALUE)

  );

事务:
四个特征:
原子性
一致性
隔离性
持久性

以银行汇款为例,张三给李四转款300元

原子性:是指某几句sql的影响,要么都发生,要么都不发生
即:张三减300,李四加300,insert银行流水,这3个操作必须都完成,或都不产生效果

一致性:事务前后的数据,保持业务上的合理一致
(汇款前)张三的余额+李四的余额 =====(汇款后)张三的余额+李四的余额
比如:张三只有280元,280-300=-20,储蓄卡不是信用卡,不能为负,因此张三0元将导致,汇款后,2者余额,汇款前差了20元

隔离性:在事务进行过程中,其他事务,看不到此事务的任何效果
持久性:事务一旦发生,不能取消,只能通过补偿性事务,来抵消效果。

你可能感兴趣的:(技术,mysql)