1、前言

最近所在项目接触到了百万级人口数据的功能开发,就这次开发也就准备记录下MySql的百万级别数量查询的设计和优化方案,技术能力受限,分享出来和大家一起讨论讨论。


2、数据准备

网上也有很多快速创建大量数据的方式,我这边提供一种可供大家参考:

#创建内存表
CREATE TABLE `t_user_memory` (`id` int(11) NOT NULL AUTO_INCREMENT,`c_user_id` varchar(36) NOT NULL DEFAULT '',`c_name` varchar(22) NOT NULL DEFAULT '',`c_province_id` int(11) NOT NULL,`c_city_id` int(11) NOT NULL,`create_time` datetime NOT NULL,PRIMARY KEY (`id`),KEY `idx_user_id` (`c_user_id`)
) ENGINE=MEMORY DEFAULT CHARSET=utf8mb4;#创建普通表
CREATE TABLE `t_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`c_user_id` varchar(36) NOT NULL DEFAULT '',`c_name` varchar(22) NOT NULL DEFAULT '',`c_province_id` int(11) NOT NULL,`c_city_id` int(11) NOT NULL,`create_time` datetime NOT NULL,PRIMARY KEY (`id`),KEY `idx_user_id` (`c_user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;#创建随机字符串
CREATE FUNCTION `randStr` ( n INT ) RETURNS VARCHAR ( 255 ) CHARSET utf8mb4 DETERMINISTIC BEGINDECLAREchars_str VARCHAR ( 100 ) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';DECLAREreturn_str VARCHAR ( 255 ) DEFAULT '';DECLAREi INT DEFAULT 0;WHILEi < n DOSET return_str = concat(return_str,substring( chars_str, FLOOR( 1 + RAND() * 62 ), 1 ));SET i = i + 1;END WHILE;RETURN return_str;
END;#创建插入数据存储过程
CREATE PROCEDURE `add_t_user_memory` ( IN n INT ) BEGINDECLAREi INT DEFAULT 1;WHILE( i <= n ) DOINSERT INTO t_user_memory ( c_user_id, c_name, c_province_id, c_city_id, create_time )VALUES(uuid(),randStr ( 20 ),FLOOR( RAND() * 1000 ),FLOOR( RAND() * 100 ),NOW());           SET i = i + 1;END WHILE;END;#循环从内存表获取数据插入普通表CREATE PROCEDURE `add_t_user_memory_to_outside`(IN n int, IN count int)BEGINDECLARE i INT DEFAULT 1;WHILE (i <= n) DOCALL add_t_user_memory(count);INSERT INTO t_user SELECT * FROM t_user_memory;delete from t_user_memory;SET i = i + 1;END WHILE;END;

调用:

#循环400次,每次生成10000条数据 总共生成四百万条数据
CALL add_t_user_memory_to_outside(400,10000);

由于我们的数据结构比较简单,我们把数据量往上调调


3、问题及解决方案

对于百万级别数据处理,通常会遇到以下几个问题:

1、分页-分页到后面的页数会越来越慢

2、分页-分页的总数conut(*)如何高效率查询

3、模糊查询如何实现双‘%’还能让索引不失效

3.1 分页-分页到后面的页数会越来越慢

我直接就上结果给大家看了:

[SQL]select * from t_user limit 0,20;
受影响的行: 0
时间: 0.002s[SQL]
select * from t_user limit 10,20;
受影响的行: 0
时间: 0.001s[SQL]
select * from t_user limit 100,20;
受影响的行: 0
时间: 0.002s[SQL]
select * from t_user limit 1000,20;
受影响的行: 0
时间: 0.001s[SQL]
select * from t_user limit 10000,20;
受影响的行: 0
时间: 0.014s[SQL]
select * from t_user limit 100000,20;
受影响的行: 0
时间: 0.057s[SQL]
select * from t_user limit 1000000,20;
受影响的行: 0
时间: 0.500s[SQL]
select * from t_user limit 3000000,20;
受影响的行: 0
时间: 1.533s

解决方式的总体思路就是把索引用上,用子查询/连接+索引快速定位数据位置

[SQL]
SELECT * FROM t_user WHERE id >=(select id from t_user limit 3000000, 1) limit 20;
受影响的行: 0
时间: 1.124s[SQL]
select * from t_user a join (select id from t_user limit 3000000,20) b on a.id = b.id;
受影响的行: 0
时间: 1.125s

3.2 分页-分页的总数conut(*)如何高效率查询

我们平时分页都是需要查询总数的,当数量级一上来,就会发现查询速率的大大降低:

ps:当时我跑生成测试数据的时候没有跑完,所以总数没有达到400w,不过并不影响优化效果

         我们进行一个简单的优化速率就大大提升了,后面有查询条件继续往后面加就是了

这次优化的重点是将原本需要分开执行的两个SQL合并,通过SQL_CALC_FOUND_ROWS函数实现:

select SQL_CALC_FOUND_ROWS *
from t_user
WHERE id > 0
LIMIT 0,20;
SELECT FOUND_ROWS() as total_num;

FOUND_ROWS()返回一个数字,指示了在没有LIMIT子句的情况下,第一个SELECT返回了多少行。

在项目中:

    <resultMap id="BaseResultMap" type="User"><id column="id" jdbcType="BIGINT" property="id"/><result column="c_name" jdbcType="VARCHAR" property="cName"/></resultMap><resultMap id="CountResultMap" type="Integer"><result column="total_num" jdbcType="INTEGER" javaType="Integer"/></resultMap><select id="getUserList" resultMap="BaseResultMap,CountResultMap">SELECT SQL_CALC_FOUND_ROWS*FROMt_userWHEREid > 0LIMIT 0,20;SELECTFOUND_ROWS() AS total_num;</select>

这里面涉及到多条结果返回,需要在配置文件application.yml的数据源加上

&allowMultiQueries=true

项目代码需要注意的点

#返回类型
List<?> getUserList();#取值
Integer totalNum = ((List<Integer>) listData.get(1)).get(0);
List<User> userList= (List<User>)listData.get(0);

3.3 模糊查询如何实现双‘%’还能让索引不失效

大家都知道,通过like '%xxx%'模糊查询会使索引失效,大数据量的情况下,会使得查询非常的缓慢,这个时候我们就可以通过全文索引(Full-Text Search)进行优化。

创建全文索引:

create fulltext index fulltext_c_name on t_user(c_name);
#可能会出现The used table type doesn't support FULLTEXT indexes报错,
查看创建表时用的哪种引擎,如果是InnoDB,改为MyISAM,在MySQL 5.6版本以前,
只有MyISAM存储引擎支持全文引擎,InnoDB不支持FULLTEXT类型的索引

使用效果:

select * from t_user where c_name like '%test%';
select * from t_user where MATCH ( c_name ) AGAINST ( '*test*' IN BOOLEAN MODE );[SQL]select * from t_user where c_name like '%test%';
受影响的行: 0
时间: 0.860s[SQL]
select * from t_user where MATCH ( c_name ) AGAINST ( '*test*' IN BOOLEAN MODE );
受影响的行: 0
时间: 0.001s

全文索引的使用和类型我就不在这边一一赘述了,这边只是给大家一个思路,同时此全文索引并不支持中文。

在MySQL 5.6版本以前,只有MyISAM存储引擎支持全文引擎,

在5.6版本中,InnoDB加入了对全文索引的支持,但是不支持中文全文索引,

在5.7.6版本,MySQL内置了ngram全文解析器,用来支持亚洲语种的分词,

在使用前请确认自己的mysql版本, 可以使用 select version() 查看mysql的版本


本次的MySql百万级数量查询优化的分享就到这里了,后续有补充我会继续更新。

MySql 百万级数量查询优化总结相关推荐

  1. MySQL百万级/千万级数据存储解决方案

    MySQL 百万级/千万级数据存储解决方案 百万级.千万级数据处理,个人认为核心关键在于数据存储方案设计,存储方案设计的是否合理,直接影响到数据CRUD操作.总体设计可以考虑一下三个方面进行设计考虑: ...

  2. MYSQL百万级数据,如何优化

    MYSQL百万级数据,如何优化 首先,数据量大的时候,应尽量避免全表扫描,应考虑在 where 及 order by 涉及的列上建立索引,建索引可以大大加快数据的检索速度.但是,有些情况索引是不会起效 ...

  3. Mysql - 百万级数据查询优化笔记 (PHP Script) ②

    Mysql - 百万级数据查询优化笔记 (PHP Script) ② 说明:要处理的是在一个脚本中统计的年度账单,和上一篇的处理思路完全 不同,先把全量取出,再按字典形式拼接,10w条数据只需要668 ...

  4. mysql 百万级数据库优化方案【转】

    一.百万级数据库优化方案 1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断 ...

  5. MySQL百万级、千万级数据多表关联SQL语句调优

    本文不涉及复杂的底层数据结构,通过explain解释SQL,并根据可能出现的情况,来做具体的优化,使百万级.千万级数据表关联查询第一页结果能在2秒内完成(真实业务告警系统优化结果). 希望读者能够理解 ...

  6. mysql百万级性能瓶颈-数据库选型

    项目中使用了mysql数据库,但数据量增长太快,不久到了百万级,很快又到表到了千万级,尝试了各种优化方式,最终效果仍难达到秒级响应,那么引发了我关于数据库选型到一些思考. 1.mysql的单表性能瓶颈 ...

  7. MySQL百万级压测数据表

    一个压测百万级数据表,数据量将近300万. 链接:提取码:ugue 说明: 这个表除了数据什么都没有,没有主键外键什么什么这那那这,方便测试用. 修改自github上的一个压测表集合:https:// ...

  8. MySQL 百万级/千万级表 总记录数查询

    业务背景:基于 InnoDB 存储引擎的表,在数据量达到百万级之后,用 count 函数查询表记录总数会变得很慢,会导致服务请求超时.针对这种情况总结下我所想到的解决办法. 实际业务场景: 表名 表名 ...

  9. php mysql百万级数据_php+mysql百万级数据怎么排序_PHP教程

    php+mysql百万级数据如何排序? php+mysql百万级数据分页.因涉及多表多条件联合查询.谁能帮忙优化下面的查询语句. if(empty($wheresql)){ $wheresql=&qu ...

最新文章

  1. 开发三年,如何摆脱日复一日的CRUD?
  2. 如何用Git拉取远程分支代码
  3. sas时间和Linux时间转化,尝试在SAS中获取文件属性(文件大小,创建日期时间和上次修改日期时间)...
  4. 分布式系统不得不说的CAP定理
  5. 别了,JavaScript;你好,Blazor
  6. Spring Cloud 学习笔记(2 / 3)
  7. java容器详解_详解Java 容器(第①篇)——概览
  8. C#.NET编程----Spring.NET NHibernate整合(一)
  9. JS节点树的一个实例
  10. 建立数组并写入数据_VBA学习笔记19:数组1
  11. sql server 中xml 数据类型的insert、update、delete
  12. 你还要我怎样的JS系列(4) -- 作用域链
  13. iOS开发需要哪些图片?
  14. 使用EasyRecovery来恢复丢失的视频
  15. Python办公自动化(四):PDF处理自动化
  16. 空调库存创新高,格力计划挖掘三四五线城市
  17. pikachu靶场学习1
  18. python分割图片、合并图片
  19. SwiftUI 内功教程之Closures 09 闭包捕捉价值Capturing Values及经典用法
  20. Elasticsearch - Fuzzy query

热门文章

  1. DEFORMABLE DETR详解
  2. Deformable DETR 论文学习
  3. 计算图像的Jacobian矩阵
  4. Windows未检测到的第二台显示器,电脑只能支持一台显示器显示,解决方法
  5. 抖音怎样报白?报白需要审核哪些资料呢
  6. 树莓派设置静态ip2
  7. 配电室常见六大安全隐患,你疏忽了几个?
  8. 技巧: Excel数据如何快速录入?
  9. pyTorch学习基础一选择CPU和GPU
  10. 【JavaScript面试】isArray() 、Array.of()、Array.from() 方法