显示标签为“mysql”的博文。显示所有博文
显示标签为“mysql”的博文。显示所有博文

2016年2月2日星期二

分页查询,你真的懂吗?

分页查询,你真的懂吗?
转自: http://www.cnblogs.com/baochuan/p/4625262.html

程序员代码的编写能力主要体现在思维的严谨上。有些看起来很简单的东西,里面包含很多很细的点,你能想到吗?
今天我就简单说一下一个例子,让大家学习到新知识的同时,也养成一种思维的习惯。

问题

有一张收藏表,里面存储的是用户和图书ID。数据量为1亿。现在要求分页获取所有用户ID(不重复),写下你的sql语句。
表结构大致如下:

1.CREATE TABLE 收藏表(
2. `id` bigint(20) unsigned NOT NULL auto_increment COMMENT 'primary key',
3. `uid` bigint(20) unsigned NOT NULL default 0 COMMENT 'uid',<br>   `status` tinyint(3) unsigned NOT NULL default 0 COMMENT 'status',
4. `book_id` bigint(20) unsigned NOT NULL default 0 COMMENT 'book Id',
5. `create_time` int(11) unsigned not null default 0 COMMENT 'create time',
6. PRIMARY KEY (`id`),
7. UNIQUE KEY `uid_book_id` (`uid`, `book_id`),<br>    KEY `uid_status` (`uid`, `status`)
8.)ENGINED=Innodb Auto_increment=1 default charset=gbk COMMENT '用户收藏信息';

三种设计

最容易想到的第一种分页语句是(这也是我们最容易想到的语句):

1.select distinct uid from 收藏表 order by uid desc limit 0, 10;
2.select distinct uid from 收藏表 order by uid desc limit 11, 10;

再高级点语句,第二种($last_min_uid表示上一次读到的最后一个uid):

1.select distinct uid from 收藏表 order by uid desc limit 10;
2.select distinct uid from 收藏表 where uid < $last_min_uid order by uid desc limit 10;

最高级的方式:

1.select uid from 收藏表 group by uid order by uid desc limit 10;
2.select uid from 收藏表 group by uid having uid < $last_min_uid order by uid desc limit 10;

分析

以上三种方式都可以实现分页获取到用户ID列表,那么区别是什么?我现在就把每一种跟大家分析下。

  • 第一种在业务场景中,会出现丢数据的情况。——这是比较严重的情况,不予采纳。

具体的业务场景是这样的:当你读取第5页的时候,前四页的用户id列表中,假如有一页的用户ID从库中删除掉,那么你这时读到的第5页(limit 51, 10),就是原来的第6页,你会把1页的用户ID丢失掉。

  • 第二种的第二条语句,通过explain分析,实际并没有命中唯一索引,而只是命中了一般索引,数据查询范围在7百万级别,故explain建议我们使用group by。——这个查询会有严重的性能问题。
1.+----+--------+-------+-------+---------+---------+----------+-------+--------+--------+
2.| id | select_type | table| type | possible_keys | key | key_len | ref | rows | Extra |
3.+----+--------+-------+-------+---------+---------+----------+-------+--------+--------+
4.| 1 | SIMPLE | ubook_room | range | uid_book_id | uid_status | 4 | NULL | 7066423 | Using where; Using index for group-by; Using temporary; Using filesort |
5.+----+--------+-------+-------+---------+---------+----------+-------+--------+--------+
  • 第三种explain分析,数据查询范围在12万级别(跟第二种相差一个数量级),查询性能高。
1.+----+--------+--------+-------+------------+--------+---------+-------+----------+--------+
2.| id| select_type| table | type | possible_keys| key | key_len | ref | rows | Extra |
3.+----+--------+--------+-------+------------+--------+---------+-------+----------+--------+
4.| 1 | SIMPLE | 收藏表 | index| NULL | uid_book_id | 12 | NULL | 121719 | Using index |
5.+----+--------+--------+-------+------------+--------+---------+-------+----------+--------+

2016年1月28日星期四

MySQL主备同步方案

MySQL主备同步方案 http://mysqllover.com/?p=810 http://mysqllover.com/?p=1370 https://yq.aliyun.com/articles/3022

MySQL优化

MySQL优化

MySQL优化

OPTIMIZE

1.REPAIR TABLE `table_name` 修复表 
2.OPTIMIZE TABLE `table_name` 优化表

  • REPAIR TABLE 用于修复被破坏的表。
  • OPTIMIZE TABLE 用于回收闲置的数据库空间,当表上的数据行被删除时,所占据的磁盘空间并没有立即被回收,使用了OPTIMIZE TABLE命令后这些空间将被回收,并且对磁盘上的数据行进行重排(注意:是磁盘上,而非数据库)。多数时间并不需要运行OPTIMIZE TABLE,只需在批量删除数据行之后,或定期(每周一次或每月一次)进行一次数据表优化操作即可,只对那些特定的表运行。

OPTIMIZE TABLE对InnoDB 和 MyISAM相关知识

  1. InnoDB 和 MyISAM
    目前支持optimize命令的引擎有 MyISAM, InnoDB, and ARCHIVE,对于InnoDB,会将optimize命令映射为ALTER TABLE命令,该命令会重建数据表,更新索引统计信息、回收主键索引中空间。
  2. InnoDB 和 MyISAM
    如果你的MySQL是有备库的,如果你只希望在主库上执行的话,那么可以加上关键字NO_WRITE_TO_BINLOG(或者LOCAL,意思完全相同)。
1.OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE

MySQL内存表&临时表

内存表::http://www.nowamagic.net/librarys/veda/detail/1405 临时表: http://tech.uc.cn/?p=2218

2015年10月29日星期四

2015年8月8日星期六

MySQL-Proxy

MySQL-Proxy是处在你的MySQL数据库客户和服务端之间的程序,它可以监测、分析或改变它们的通信,它还支持嵌入性脚本语言Lua。这个代理可以用来分析、监控和变换(transform)通信数据,它支持非常广泛的使用场景:
  • 负载平衡和故障转移处理
  • 查询分析和日志
  • SQL宏(SQL macros)
  • 查询重写(query rewriting)
  • 执行shell命令
简单的说,MySQL Proxy就是一个连接池,负责将前台应用的连接请求转发给后台的数据库,并且通过使用lua脚本,可以实现复杂的连接控制和过滤,从而实现读写分离和负载平衡。对于应用来说,MySQL Proxy是完全透明的,应用则只需要连接到MySQL Proxy的监听端口即可。当然,这样proxy机器可能成为单点失效,但完全可以使用多个proxy机器做为冗余,在应用服务器的连接池配置中配置到多个proxy的连接参数即可。
MySQL Proxy更强大的一项功能是实现“读写分离(Read/Write Splitting)”。基本的原理是让主数据库处理事务性查询,而从数据库处理SELECT查询。数据库复制被用来把事务性查询导致的变更同步到集群中的从数据库。


读写分离:
http://imysql.cn/2008_04_23_quick_startup_with_mysql_proxy
http://blog.csdn.net/yueliangdao0608/article/details/2398655