[sql]分页查询
2016-07-21 16:58
357 查看
程序员代码的编写能力主要体现在思维的严谨上。有些看起来很简单的东西,里面包含很多很细的点,你能想到吗?今天我就简单说一下一个例子,让大家学习到新知识的同时,也养成一种思维的习惯。
有一张收藏表,里面存储的是用户和图书ID。数据量为1亿。现在要求分页获取所有用户ID(不重复),写下你的sql语句。
表结构大致如下:
MySQL
再高级点语句,第二种($last_min_uid表示上一次读到的最后一个uid):
MySQL
最高级的方式MySQL
以上三种方式都可以实现分页获取到用户ID列表,那么区别是什么?我现在就把每一种跟大家分析下。
第一种在业务场景中,会出现丢数据的情况。——这是比较严重的情况,不予采纳。
具体的业务场景是这样的:当你读取第5页的时候,前四页的用户id列表中,假如有一页的用户ID从库中删除掉,那么你这时读到的第5页(limit 51, 10),就是原来的第6页,你会把1页的用户ID丢失掉。
第二种的第二条语句,通过explain分析,实际并没有命中唯一索引,而只是命中了一般索引,数据查询范围在7百万级别,故explain建议我们使用group by。——这个查询会有严重的性能问题。
MySQL
第三种explain分析,数据查询范围在12万级别(跟第二种相差一个数量级),查询性能高。MySQL
有一张收藏表,里面存储的是用户和图书ID。数据量为1亿。现在要求分页获取所有用户ID(不重复),写下你的sql语句。
表结构大致如下:
MySQL
12345678 | CREATE TABLE 收藏表( `id` bigint(20) unsigned NOT NULL auto_increment COMMENT 'primary key', `uid` bigint(20) unsigned NOT NULL default 0 COMMENT 'uid',<br> `status` tinyint(3) unsigned NOT NULL default 0 COMMENT 'status', `book_id` bigint(20) unsigned NOT NULL default 0 COMMENT 'book Id', `create_time` int(11) unsigned not null default 0 COMMENT 'create time', PRIMARY KEY (`id`), UNIQUE KEY `uid_book_id` (`uid`, `book_id`),<br> KEY `uid_status` (`uid`, `status`))ENGINED=Innodb Auto_increment=1 default charset=gbk COMMENT '用户收藏信息'; |
三种设计
最容易想到的第一种分页语句是(这也是我们最容易想到的语句):MySQL1 2 | select distinct uid from 收藏表 order by uid desc limit 0, 10; select distinct uid from 收藏表 order by uid desc limit 11, 10; |
MySQL
12 | select distinct uid from 收藏表 order by uid desc limit 10;select distinct uid from 收藏表 where uid < $last_min_uid order by uid desc limit 10; |
1 2 | select uid from 收藏表 group by uid order by uid desc limit 10; 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。——这个查询会有严重的性能问题。
MySQL
12345 | +----+--------------+---------------+-------+-------------------| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+--------------+---------------+-------+-------------------| 1 | SIMPLE | ubook_room | range | uid_book_id | uid_status | 4 | NULL | 7066423 | Using where; Using index for group-by; Using temporary; Using filesort | +----+--------------+---------------+-------+------------------- |
1 2 3 4 5 | +----+--------------+---------------+-------+------------------- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+---------------+------------+-------+-----------------+-----------------+---------+--- | 1 | SIMPLE | 收藏表 | index | NULL | uid_book_id | 12 | NULL | 121719 | Using index | +----+---------------+------------+-------+-----------------+-----------------+---------+--- |
相关文章推荐
- Oracle学习记录整理笔记3-默认的管理表
- CentOS6.5下redis3.2.1安装
- Oracle SOA Suite OverView
- [Magento SQL] 按天统计产品的浏览量
- SQL语句简单代码
- Redis 集群cluster
- CodeSmith部署安装以及编写MySQL模板的时候无法获取description
- oracle12c cdb和pdb参数修改
- How MySQL Opens and Closes Tables
- 在ABP中通过EF直接执行原生Sql的解决方案
- SQL中union的常用用法~~解决数据拼凑、表中两列合并等问题
- MongoDB 安装以及系统服务配置方法
- jtds 链接服务器 tds protocol error invalid table tab_name_token
- oracle创建job权限
- sql---cast函数
- mac下通过brew安装mysql
- Mysql Create命令小结
- VS2015 +EF6 连接MYSQL数据库生成实体
- 解决 oracle IO占用率很高的问题
- 解决 oracle IO占用率很高的问题