- 浏览: 167350 次
- 性别:
- 来自: 南京
文章分类
- 全部博客 (158)
- 每天工作日志 (64)
- php工作遇到技术难题记录 (4)
- linux成长记录 (17)
- web前端开发记录 (12)
- SQL成长记录 (16)
- joomla开发记录 (0)
- 开发工具使用记录 (1)
- vpn简单安装 (0)
- 直接查询字段结果进行以逗号分隔,不用在php代码中进行foreach循环处理 (1)
- phalcon项目搭建 (1)
- java项目实践 (5)
- share everythings (0)
- Mac工作记录 (3)
- 闲文杂谈 (6)
- 细说javascript面向对象 (0)
- 瞎几把扯 (2)
- Shell编程学习与分享 (0)
- GO语言开发 (5)
- angular2 (1)
- Go开发 (3)
- java开发 (15)
最新评论
-
弹指一世界:
感谢博主分享,但是我把项目下载下来放本地运行报了一个错误Exc ...
php phalcon项目实战 -
xialluyouyue:
...
php xmlrpc的简单实用
有一张财务流水表,未分库分表,目前的数据量为9555695,分页查询使用到了limit,优化之前的查询耗时16 s 938 ms (execution: 16 s 831 ms, fetching: 107 ms),按照下文的方式调整SQL后,耗时347 ms (execution: 163 ms, fetching: 184 ms);
操作:查询条件放到子查询中,子查询只查主键ID,然后使用子查询中确定的主键关联查询其他的属性字段;
原理:减少回表操作;
-- 优化前SQL
SELECT 各种字段
FROM `table_name`
WHERE 各种条件
LIMIT 0,10;
-- 优化后SQL
SELECT 各种字段
FROM `table_name` main_tale
RIGHT JOIN
(
SELECT 子查询只查主键
FROM `table_name`
WHERE 各种条件
LIMIT 0,10;
) temp_table ON temp_table.主键 = main_table.主键
一,前言
首先说明一下MySQL的版本:
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.17 |
+-----------+
1 row in set (0.00 sec)
表结构:
mysql> desc test;
+--------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| val | int(10) unsigned | NO | MUL | 0 | |
| source | int(10) unsigned | NO | | 0 | |
+--------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
id为自增主键,val为非唯一索引。
灌入大量数据,共500万:
mysql> select count(*) from test;
+----------+
| count(*) |
+----------+
| 5242882 |
+----------+
1 row in set (4.25 sec)
我们知道,当limit offset rows中的offset很大时,会出现效率问题:
mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id | val | source |
+---------+-----+--------+
| 3327622 | 4 | 4 |
| 3327632 | 4 | 4 |
| 3327642 | 4 | 4 |
| 3327652 | 4 | 4 |
| 3327662 | 4 | 4 |
+---------+-----+--------+
5 rows in set (15.98 sec)
为了达到相同的目的,我们一般会改写成如下语句:
mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id | val | source | id |
+---------+-----+--------+---------+
| 3327622 | 4 | 4 | 3327622 |
| 3327632 | 4 | 4 | 3327632 |
| 3327642 | 4 | 4 | 3327642 |
| 3327652 | 4 | 4 | 3327652 |
| 3327662 | 4 | 4 | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.38 sec)
时间相差很明显。
为什么会出现上面的结果?我们看一下select * from test where val=4 limit 300000,5;的查询过程:
查询到索引叶子节点数据。
根据叶子节点上的主键值去聚簇索引上查询需要的全部字段值。
类似于下面这张图:
像上面这样,需要查询300005次索引节点,查询300005次聚簇索引的数据,最后再将结果过滤掉前300000条,取出最后5条。MySQL耗费了大量随机I/O在查询聚簇索引的数据上,而有300000次随机I/O查询到的数据是不会出现在结果集当中的。
肯定会有人问:既然一开始是利用索引的,为什么不先沿着索引叶子节点查询到最后需要的5个节点,然后再去聚簇索引中查询实际数据。这样只需要5次随机I/O,类似于下面图片的过程:
其实我也想问这个问题。
证实
下面我们实际操作一下来证实上述的推论:
为了证实select * from test where val=4 limit 300000,5是扫描300005个索引节点和300005个聚簇索引上的数据节点,我们需要知道MySQL有没有办法统计在一个sql中通过索引节点查询数据节点的次数。我先试了Handler_read_*系列,很遗憾没有一个变量能满足条件。
我只能通过间接的方式来证实:
InnoDB中有buffer pool。里面存有最近访问过的数据页,包括数据页和索引页。所以我们需要运行两个sql,来比较buffer pool中的数据页的数量。预测结果是运行select * from test a inner join (select id from test where val=4 limit 300000,5); 之后,buffer pool中的数据页的数量远远少于select * from test where val=4 limit 300000,5;对应的数量,因为前一个sql只访问5次数据页,而后一个sql访问300005次数据页。
select * from test where val=4 limit 300000,5
mysql> select index_name,count(*) from
information_schema.INNODB_BUFFER_PAGE where
INDEX_NAME in('val','primary') and TABLE_NAME like '%test%'
group by index_name;Empty set (0.04 sec)
可以看出,目前buffer pool中没有关于test表的数据页。
mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id | val | source |
+---------+-----+--------+|
3327622 | 4 | 4 |
| 3327632 | 4 | 4 |
| 3327642 | 4 | 4 |
| 3327652 | 4 | 4 |
| 3327662 | 4 | 4 |
+---------+-----+--------+
5 rows in set (26.19 sec)
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| PRIMARY | 4098 |
| val | 208 |
+------------+----------+2 rows in set (0.04 sec)
可以看出,此时buffer pool中关于test表有4098个数据页,208个索引页。
select * from test a inner join (select id from test where val=4 limit 300000,5) ;为了防止上次试验的影响,我们需要清空buffer pool,重启mysql。
mysqladmin shutdown
/usr/local/bin/mysqld_safe &
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
Empty set (0.03 sec)
运行sql:
mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id | val | source | id |
+---------+-----+--------+---------+
| 3327622 | 4 | 4 | 3327622 |
| 3327632 | 4 | 4 | 3327632 |
| 3327642 | 4 | 4 | 3327642 |
| 3327652 | 4 | 4 | 3327652 |
| 3327662 | 4 | 4 | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.09 sec)
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| PRIMARY | 5 |
| val | 390 |
+------------+----------+
2 rows in set (0.03 sec)
我们可以看明显的看出两者的差别:第一个sql加载了4098个数据页到buffer pool,而第二个sql只加载了5个数据页到buffer pool。符合我们的预测。也证实了为什么第一个sql会慢:读取大量的无用数据行(300000),最后却抛弃掉。
而且这会造成一个问题:加载了很多热点不是很高的数据页到buffer pool,会造成buffer pool的污染,占用buffer pool的空间。遇到的问题
为了在每次重启时确保清空buffer pool,我们需要关闭innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup,这两个选项能够控制数据库关闭时dump出buffer pool中的数据和在数据库开启时载入在磁盘上备份buffer pool的数据。
操作:查询条件放到子查询中,子查询只查主键ID,然后使用子查询中确定的主键关联查询其他的属性字段;
原理:减少回表操作;
-- 优化前SQL
SELECT 各种字段
FROM `table_name`
WHERE 各种条件
LIMIT 0,10;
-- 优化后SQL
SELECT 各种字段
FROM `table_name` main_tale
RIGHT JOIN
(
SELECT 子查询只查主键
FROM `table_name`
WHERE 各种条件
LIMIT 0,10;
) temp_table ON temp_table.主键 = main_table.主键
一,前言
首先说明一下MySQL的版本:
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.17 |
+-----------+
1 row in set (0.00 sec)
表结构:
mysql> desc test;
+--------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| val | int(10) unsigned | NO | MUL | 0 | |
| source | int(10) unsigned | NO | | 0 | |
+--------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
id为自增主键,val为非唯一索引。
灌入大量数据,共500万:
mysql> select count(*) from test;
+----------+
| count(*) |
+----------+
| 5242882 |
+----------+
1 row in set (4.25 sec)
我们知道,当limit offset rows中的offset很大时,会出现效率问题:
mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id | val | source |
+---------+-----+--------+
| 3327622 | 4 | 4 |
| 3327632 | 4 | 4 |
| 3327642 | 4 | 4 |
| 3327652 | 4 | 4 |
| 3327662 | 4 | 4 |
+---------+-----+--------+
5 rows in set (15.98 sec)
为了达到相同的目的,我们一般会改写成如下语句:
mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id | val | source | id |
+---------+-----+--------+---------+
| 3327622 | 4 | 4 | 3327622 |
| 3327632 | 4 | 4 | 3327632 |
| 3327642 | 4 | 4 | 3327642 |
| 3327652 | 4 | 4 | 3327652 |
| 3327662 | 4 | 4 | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.38 sec)
时间相差很明显。
为什么会出现上面的结果?我们看一下select * from test where val=4 limit 300000,5;的查询过程:
查询到索引叶子节点数据。
根据叶子节点上的主键值去聚簇索引上查询需要的全部字段值。
类似于下面这张图:
像上面这样,需要查询300005次索引节点,查询300005次聚簇索引的数据,最后再将结果过滤掉前300000条,取出最后5条。MySQL耗费了大量随机I/O在查询聚簇索引的数据上,而有300000次随机I/O查询到的数据是不会出现在结果集当中的。
肯定会有人问:既然一开始是利用索引的,为什么不先沿着索引叶子节点查询到最后需要的5个节点,然后再去聚簇索引中查询实际数据。这样只需要5次随机I/O,类似于下面图片的过程:
其实我也想问这个问题。
证实
下面我们实际操作一下来证实上述的推论:
为了证实select * from test where val=4 limit 300000,5是扫描300005个索引节点和300005个聚簇索引上的数据节点,我们需要知道MySQL有没有办法统计在一个sql中通过索引节点查询数据节点的次数。我先试了Handler_read_*系列,很遗憾没有一个变量能满足条件。
我只能通过间接的方式来证实:
InnoDB中有buffer pool。里面存有最近访问过的数据页,包括数据页和索引页。所以我们需要运行两个sql,来比较buffer pool中的数据页的数量。预测结果是运行select * from test a inner join (select id from test where val=4 limit 300000,5); 之后,buffer pool中的数据页的数量远远少于select * from test where val=4 limit 300000,5;对应的数量,因为前一个sql只访问5次数据页,而后一个sql访问300005次数据页。
select * from test where val=4 limit 300000,5
mysql> select index_name,count(*) from
information_schema.INNODB_BUFFER_PAGE where
INDEX_NAME in('val','primary') and TABLE_NAME like '%test%'
group by index_name;Empty set (0.04 sec)
可以看出,目前buffer pool中没有关于test表的数据页。
mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id | val | source |
+---------+-----+--------+|
3327622 | 4 | 4 |
| 3327632 | 4 | 4 |
| 3327642 | 4 | 4 |
| 3327652 | 4 | 4 |
| 3327662 | 4 | 4 |
+---------+-----+--------+
5 rows in set (26.19 sec)
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| PRIMARY | 4098 |
| val | 208 |
+------------+----------+2 rows in set (0.04 sec)
可以看出,此时buffer pool中关于test表有4098个数据页,208个索引页。
select * from test a inner join (select id from test where val=4 limit 300000,5) ;为了防止上次试验的影响,我们需要清空buffer pool,重启mysql。
mysqladmin shutdown
/usr/local/bin/mysqld_safe &
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
Empty set (0.03 sec)
运行sql:
mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id | val | source | id |
+---------+-----+--------+---------+
| 3327622 | 4 | 4 | 3327622 |
| 3327632 | 4 | 4 | 3327632 |
| 3327642 | 4 | 4 | 3327642 |
| 3327652 | 4 | 4 | 3327652 |
| 3327662 | 4 | 4 | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.09 sec)
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| PRIMARY | 5 |
| val | 390 |
+------------+----------+
2 rows in set (0.03 sec)
我们可以看明显的看出两者的差别:第一个sql加载了4098个数据页到buffer pool,而第二个sql只加载了5个数据页到buffer pool。符合我们的预测。也证实了为什么第一个sql会慢:读取大量的无用数据行(300000),最后却抛弃掉。
而且这会造成一个问题:加载了很多热点不是很高的数据页到buffer pool,会造成buffer pool的污染,占用buffer pool的空间。遇到的问题
为了在每次重启时确保清空buffer pool,我们需要关闭innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup,这两个选项能够控制数据库关闭时dump出buffer pool中的数据和在数据库开启时载入在磁盘上备份buffer pool的数据。
发表评论
-
mysql的sql_mode合理设置(转)
2017-01-22 09:15 424MySQL的sql_mode合理设置 sql_mode是个 ... -
统计sql整理
2016-10-28 11:21 395项目统计sql记录: 获取不同诚信等级的企业数 1:首 ... -
自定义函数 pgsql
2016-06-27 17:38 11491:经纬度计算距离 DECLARE dx floa ... -
常见的sql优化
2015-06-09 11:09 4621.对查询进行优化,应 ... -
使用Explain分析SQL
2015-06-08 15:06 647如果 ... -
MYSQL:SQL_CALC_FOUND_ROWS和count(*)性能比较
2015-04-10 17:31 988使用覆盖索引情况下,使用SQL_CALC_FOUND_ROWS ... -
Mysql初始化root密码和允许远程访问(转)
2015-04-06 15:40 537Mysql初始化root密码和允许远程访问 2009-09 ... -
MySQL主从复制与读写分离
2014-12-01 21:46 522项目中遇到的数据问题 ... -
sql数据库 命令行操作
2014-03-12 18:34 706命令行 1、显示当前 ... -
MySQL中TIMESTAMPDIFF和TIMESTAMPADD函数的用法
2014-02-08 10:49 0MySQL中TIMESTAMPDIFF和TIMESTAMPA ... -
Mysql CONCAT IF 的运用
2013-12-12 09:39 1190简单的查询使用CONCAT IF $query=&qu ... -
sql对于json数据里面的key值我们如何排序
2013-11-17 22:14 1033首先我们创建一个表json用于存储json数据,我们对其中的 ... -
SQL_CALC_FOUND_ROWS 的使用问题(笔记)
2013-11-11 14:32 1606mysql> select SQL_CALC_FOUN ... -
(转)经典SQL查询语句大全
2013-11-04 14:05 994一、基础1、说明:创建数据库CREATE DATABASE ... -
mysql的DUPLICATE KEY
2013-10-20 18:49 853经常遇到这样的情景,向一个表里插入一条数据,如果已经存在就更 ... -
数据库中in与exists的区别.txt
2013-10-20 18:38 456对于in与exists的区别: ...
相关推荐
16s rRNA基因,全称为16s ribosomal RNA基因,是细菌、古菌以及线粒体等细胞器中的核糖体RNA的一个亚基,它在细胞的蛋白质合成过程中起到重要作用。16s rDNA则是该基因的DNA序列,包含在细菌的染色体基因组中。由于...
同时,其内部的程序存储器与数据存储器(SRAM)提供了充足的存储空间,满足复杂的程序执行和数据处理需求。 ### I/O口结构与配置 手册深入介绍了STC12C5A16S2的I/O口结构,包括P4/P5口的使用方法,以及I/O口在不同...
《使用QIIME 2分析微生物组16S rRNA基因扩增子测序数据》 微生物组研究在近年来已经成为生命科学研究的热点,其中16S rRNA基因扩增子测序技术因其高通量、成本效益高的特性,被广泛用于微生物群落结构的解析。QIIME...
本文将详细介绍如何使用QIIME 2进行16S rRNA基因扩增子测序数据的分析。 首先,QIIME 2采用了Python 3作为基础语言,确保了与最新的算法和技术兼容,同时支持交互式图表,增强了数据可视化功能。此外,QIIME 2的...
16S扩增子多样性测序平台、测序数据量选择汇总.pdf16S扩增子多样性测序平台、测序数据量选择汇总.pdf16S扩增子多样性测序平台、测序数据量选择汇总.pdf16S扩增子多样性测序平台、测序数据量选择汇总.pdf16S扩增子...
从宏基因组学数据回收16S核糖体RNA的组装工具 依存关系: 地狱1.1.1 Readjoiner 1.2 Runbook: 输入:FASTA格式的双端宏基因组读取 输出:从宏基因组读取中回收的16S基因 步骤1:确定16S读取。 命令:python ...
技术规格方面,MY1680U-16S支持的音频文件采样率在8到48K之间,比特率则覆盖了8到320Kbps。它具备24位数字模拟转换器(DAC)输出,拥有93dB的动态范围和85dB的信噪比表现。该芯片支持最大16MByte的FLASH存储空间,...
- 开发过程中,需要编写C语言程序来控制STC12C5A16S2执行AD采集和串口通信任务。 - 程序结构通常包括初始化部分(配置AD转换器和串口)、主循环(定期采集和发送数据)以及中断服务子程序(处理串口发送完成事件)...
STC12C5A16S_YX5200是基于STC12C5A16S单片机实现的一种MP3播放器方案,主要利用了单片机的UART2串行接口进行通信。这个项目的核心在于将单片机与YX5200 MP3解码芯片进行连接,通过串口2(UART2)进行数据传输,以...
魅族16s刷写第三方twrp+实测步骤教程 1----请使用本人实测的资源来刷写你的机型 2----资源可以支持当前机型刷写第三方rec 3-----内含刷写资源和详细刷写教程步骤 4-----完美兼容当前不同的版本刷写 5-----资源...
16S核糖体RNA(16S rRNA)是核糖体中30S亚基的组成成分,是一种存在于所有生物的核糖体中,是细胞蛋白质合成的中心。16S rRNA是核糖体的多个RNA组件之一,在细胞的蛋白质合成过程中起着关键作用,它不仅对核糖体结构...
MY1690-16S 是深圳市迈优科技有限公司自主研发的一款由串口控制的插卡MP3芯片。支持MP3、WAV格式双解码,模块最大支持32G TF卡,也可外接U盘或USB数据线连接电脑更换SD卡音频文件。
**16S rDNA扩增子测序技术详解** 16S rDNA是细菌和古菌基因组中保守的核糖体RNA(rRNA)序列,由于其在不同物种间的高度保守性和在种内高度多态性,16S rDNA成为微生物分类和群落结构分析的重要分子标记。16S rDNA...
16S扩增子测序分析流程是一门应用于微生物群落研究的技术,其目的在于分析特定环境中微生物群体的基因组成、功能、多样性和丰度,并进而研究微生物与环境、宿主之间的相互关系。该技术基于宏基因组测序的概念,它与...
"病原微生物检测之16s与宏基因组" 病原微生物检测是微生物学中的一个重要领域,而16S和宏基因组是其中两个关键技术。本文将对病原微生物检测之16S与宏基因组进行详细的介绍和分析。 微生物基本概念 微生物...
魅族16s售后9008线刷救砖固件 版本7.3.0.1A,亲自实验100%成功
在口腔微生物学和龋病研究领域中,16S rRNA克隆文库法是一种广泛应用于微生物种群结构分析的技术。该方法基于16S rRNA基因的序列信息,它是原核生物核糖体中的一种核糖核酸,由于其编码区域高度保守而适合作为微生物...
5. 机械数据:设备的最大导线截面为300mm²,适用于单芯或多芯导线,拥有插接连接器。尺寸为87x45x121mm,重量为330克。 6. 运行模式:PNOZ16/PNOZ16S支持单通道操作和双通道操作,提供自动复位和手动复位的功能。 ...
- **软件优化**:优化控制算法,降低延迟,提高飞行器的动态响应和稳定性。 通过以上对STC8A8K16S4A12及其在四轴飞控中的应用的详细阐述,我们可以看到,这个微控制器在四轴飞行器的控制系统中扮演了至关重要的...
本资源内容包括:9008线刷工具与驱动、魅族16s Flyme 7.3.0.0A(出厂系统线刷包),以及降级救砖教程。 此降级方法将会清除所有数据,刷机前请做好备份。 刷机前请确保手机能正常开/关机,本教程不可清除锁屏密码,...