28 | 案例篇:一个SQL查询要15秒,这是怎么回事?
案例准备
- 机器配置:2 CPU,8GB 内存
- 预先安装 docker、sysstat 、git、make 等工具,如 apt install docker.io sysstat make git
- /:返回 Index Page;
- /db/insert/products/:插入指定数量的商品信息;
- /products/:查询指定商品的信息,并返回处理时间。
案例分析
$ git clone https://github.com/feiskyer/linux-perf-examples
$ cd linux-perf-examples/mysql-slow
# 注意下面的随机字符串是容器 ID,每次运行均会不同,并且你不需要关注它,因为我们只会用到名字
$ make run
docker run --name=mysql -itd -p 10000:80 -m 800m feisky/mysql:5.6
WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.
4156780da5be0b9026bcf27a3fa56abc15b8408e358fa327f472bcc5add4453f
docker run --name=dataservice -itd --privileged feisky/mysql-dataservice
f724d0816d7e47c0b2b1ff701e9a39239cb9b5ce70f597764c793b68131122bb
docker run --name=app --network=container:mysql -itd feisky/mysql-slow
81d3392ba25bb8436f6151662a13ff6182b6bc6f2a559fc2e9d873cd07224ab6
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9a4e3c580963 feisky/mysql-slow "python /app.py" 42 seconds ago Up 36 seconds app
2a47aab18082 feisky/mysql-dataservice "python /dataservice…" 46 seconds ago Up 41 seconds dataservice
4c3ff7b24748 feisky/mysql:5.6 "docker-entrypoint.s…" 47 seconds ago Up 46 seconds 3306/tcp, 0.0.0.0:10000->80/tcp mysql
$ docker logs -f mysql
...
... [Note] mysqld: ready for connections.
Version: '5.6.42-log' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
$ curl http://127.0.0.1:10000/
Index Page
$ make init
docker exec -i mysql mysql -uroot -P3306 < tables.sql
curl http://127.0.0.1:10000/db/insert/products/10000
insert 10000 lines
$ curl http://192.168.0.10:10000/products/geektime
Got data: () in 15.364538192749023 sec
$ while true; do curl http://192.168.0.10:10000/products/geektime; sleep 5; done
$ top
top - 12:02:15 up 6 days, 8:05, 1 user, load average: 0.66, 0.72, 0.59
Tasks: 137 total, 1 running, 81 sleeping, 0 stopped, 0 zombie
%Cpu0 : 0.7 us, 1.3 sy, 0.0 ni, 35.9 id, 62.1 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.3 us, 0.7 sy, 0.0 ni, 84.7 id, 14.3 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 8169300 total, 7238472 free, 546132 used, 384696 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 7316952 avail MemPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
27458 999 20 0 833852 57968 13176 S 1.7 0.7 0:12.40 mysqld
27617 root 20 0 24348 9216 4692 S 1.0 0.1 0:04.40 python1549 root 20 0 236716 24568 9864 S 0.3 0.3 51:46.57 python3
22421 root 20 0 0 0 0 I 0.3 0.0 0:01.16 kworker/u
$ iostat -d -x 1
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
...
sda 273.00 0.00 32568.00 0.00 0.00 0.00 0.00 0.00 7.90 0.00 1.16 119.30 0.00 3.56 97.20
# -d 选项表示展示进程的 I/O 情况
$ pidstat -d 1
12:04:11 UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
12:04:12 999 27458 32640.00 0.00 0.00 0 mysqld
12:04:12 0 27617 4.00 4.00 0.00 3 python
12:04:12 0 27864 0.00 4.00 0.00 0 systemd-journal
$ strace -f -p 27458
[pid 28014] read(38, "934EiwT363aak7VtqF1mHGa4LL4Dhbks"..., 131072) = 131072
[pid 28014] read(38, "hSs7KBDepBqA6m4ce6i6iUfFTeG9Ot9z"..., 20480) = 20480
[pid 28014] read(38, "NRhRjCSsLLBjTfdqiBRLvN9K6FRfqqLm"..., 131072) = 131072
[pid 28014] read(38, "AKgsik4BilLb7y6OkwQUjjqGeCTQTaRl"..., 24576) = 24576
[pid 28014] read(38, "hFMHx7FzUSqfFI22fQxWCpSnDmRjamaW"..., 131072) = 131072
[pid 28014] read(38, "ajUzLmKqivcDJSkiw7QWf2ETLgvQIpfC"..., 20480) = 20480
$ lsof -p 28014
$ echo $?
1
# -t 表示显示线程,-a 表示显示命令行参数
$ pstree -t -a -p 27458
mysqld,27458 --log_bin=on --sync_binlog=1
...├─{mysqld},27922├─{mysqld},27923└─{mysqld},28014
$ lsof -p 27458
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
...
mysqld 27458 999 38u REG 8,1 512440000 2601895 /var/lib/mysql/test/products.MYD
- MYD 文件,是 MyISAM 引擎用来存储表数据的文件;
- 文件名就是数据表的名字;
- 而这个文件的父目录,也就是数据库的名字。
$ docker exec -it mysql ls /var/lib/mysql/test/
db.opt products.MYD products.MYI products.frm
- MYD 文件用来存储表的数据;
- MYI 文件用来存储表的索引;
- frm 文件用来存储表的元信息(比如表结构);
- opt 文件则用来存储数据库的元信息(比如字符集、字符校验规则等)。
$ docker exec -i -t mysql mysql -e 'show global variables like "%datadir%";'
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| datadir | /var/lib/mysql/ |
+---------------+-----------------+
$ docker exec -i -t mysql mysql
...
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
mysql> show full processlist;
+----+------+-----------------+------+---------+------+--------------+-----------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------------+------+---------+------+--------------+-----------------------------------------------------+
| 27 | root | localhost | test | Query | 0 | init | show full processlist |
| 28 | root | 127.0.0.1:42262 | test | Query | 1 | Sending data | select * from products where productName='geektime' |
+----+------+-----------------+------+---------+------+--------------+-----------------------------------------------------+
2 rows in set (0.00 sec)
- db 表示数据库的名字;
- Command 表示 SQL 类型;
- Time 表示执行时间;
- State 表示状态;
- 而 Info 则包含了完整的 SQL 语句。
# 切换到 test 库
mysql> use test;
# 执行 explain 命令
mysql> explain select * from products where productName='geektime';
+----+-------------+----------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------+---------+------+-------+-------------+
| 1 | SIMPLE | products | ALL | NULL | NULL | NULL | NULL | 10000 | Using where |
+----+-------------+----------+------+---------------+------+---------+------+-------+-------------+
1 row in set (0.00 sec)
- select_type 表示查询类型,而这里的 SIMPLE 表示此查询不包括 UNION 查询或者子查询;
- table 表示数据表的名字,这里是 products;
- type 表示查询类型,这里的 ALL 表示全表查询,但索引查询应该是 index 类型才对;
- possible_keys 表示可能选用的索引,这里是 NULL;
- key 表示确切会使用的索引,这里也是 NULL;
- rows 表示查询扫描的行数,这里是 10000。
mysql> show create table products;
...
| products | CREATE TABLE `products` (`id` int(11) NOT NULL,`productCode` text NOT NULL COMMENT '产品代码',`productName` text NOT NULL COMMENT '产品名称',
...PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC |
...
mysql> CREATE INDEX products_index ON products (productName);
ERROR 1170 (42000): BLOB/TEXT column 'productName' used in key specification without a key length
mysql> CREATE INDEX products_index ON products (productName(64));
Query OK, 10000 rows affected (14.45 sec)
Records: 10000 Duplicates: 0 Warnings: 0
Got data: ()in 15.383180141448975 sec
Got data: ()in 15.384996891021729 sec
Got data: ()in 0.0021054744720458984 sec
Got data: ()in 0.003951072692871094 sec
案例思考
# 删除索引
$ docker exec -i -t mysql mysql
mysql> use test;
mysql> DROP INDEX products_index ON products;
$ while true; do curl http://192.168.0.10:10000/products/geektime; sleep 5; done
Got data: ()in 16.884345054626465 sec
# 停止 DataService 应用
$ docker rm -f dataservice
Got data: ()in 16.884345054626465 sec
Got data: ()in 15.238174200057983 sec
Got data: ()in 0.12604427337646484 sec
Got data: ()in 0.1101069450378418 sec
Got data: ()in 0.11235237121582031 sec
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st0 1 0 6809304 1368 856744 0 0 32640 0 52 478 1 0 50 49 00 1 0 6776620 1368 889456 0 0 32640 0 33 490 0 0 50 49 00 0 0 6747540 1368 918576 0 0 29056 0 42 568 0 0 56 44 00 0 0 6747540 1368 918576 0 0 0 0 40 141 1 0 100 0 00 0 0 6747160 1368 918576 0 0 0 0 40 148 0 1 99 0 0
小结
28 | 案例篇:一个SQL查询要15秒,这是怎么回事?相关推荐
- 编写一个 SQL 查询来实现分数排名
每日一题,第一篇 1.编写一个 SQL 查询来实现分数排名. 如果两个分数相同,则两个分数排名(Rank)相同.请注意,平分后的下一个名次应该是下一个连续的整数值.换句话说,名次之间不应该有" ...
- 编写一个 SQL 查询,找出每个部门工资最高的员工。
Employee 表包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id.+----+-------+--------+--------------+ | Id ...
- 面试官:编写一个 SQL 查询,找出每个部门工资第二高的员工
今天我们来看看大数据开发中row_number函数. 作为一名程序员,求职面试时时常会遇到需要编写一些基础的sql,编写sql这样做的目的主要是考验求职者的逻辑思维及编写sql基础能力.而row_nu ...
- 使用一个SQL查询出每门课程的成绩都大于80分的学生姓名
使用一个SQL查询出每门课程的成绩都大于80分的学生姓名 表名为student,字段和数据如下用一条SQL语句查询出student表中每门功课都大于80分的学生姓名. name kecheng fen ...
- 用一个sql查询将url匹配的排在最前,title匹配的其次,body匹配最后
假设只有一个table,名为pages,有四个字段,id, url,title,body.里面储存了很多网页,网页的url地址,title和网页的内容,然后你用一个sql查询将url匹配的排在最前,t ...
- mysql查询每门功课成绩最好的前两名_用一个SQL查询语句得出每门功课成绩最好的前两名 - SQL Server论坛 - 51CTO技术论坛_中国领先的IT技术社区...
有一个学生表,里面有 学号 功课编号 学生成绩三个字段. 用一个SQL查询语句得出每门功课成绩最好的前两名 学号 功课编号 学生成绩 1 1 99 ...
- 编写一个 SQL 查询,来删除 Person表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。
题目 编写一个 SQL 查询,来删除 Person表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小的那个. Id Email 1 john@example.com 2 bob@example.c ...
- 编写一个 SQL 查询,来删除 Person表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。
题目 编写一个 SQL 查询,来删除 Person表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个. +----+------------------+ | Id | Email | + ...
- 编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息:
表1为Penson,表2为Address,如下图所示 要求:编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息: FirstName ...
最新文章
- 并查集hdu1232
- C++环境测试CPU是否支持MMX,SSE-未完
- mysql日期时间函数(常用的)
- 跨链(6)波卡Polkadot “系统框架”
- 浅析ASP.NET回车提交事件[转]
- 图论--树的直径--DFS+树形DP模板
- mysql 左连接 重复_mysql左连接重复行
- C语言 变量声明和定义的区别
- go tcp连接_TCP漫谈之keepalive和time_wait
- fullcalendar php,日历插件fullcalendar+php的使用教程 — 读取json数据
- Opencv3 形态学操作
- 360集团或将推出数字安全免费新品
- 4-1-getOutputStream()或getWriter()发送响应消息体及分析为什么不能同时使用
- 英特尔推出业界领先的AI与数据分析平台,全新处理器、内存、存储、FPGA解决方案集体亮相
- 计算机信息网络功能修改,IP地址自动修改的功能移植
- C++标准程序库读书笔记-第二章新的语言特性
- 数据库的增加,删除,更新操作--mysql
- [手机Linux]一,线刷小米6到开发版,获取root权限
- php 图片 字母识别,PHP图片文字识别(OCR)
- 山东省第二届数据应用创新大赛日照赛区-公积金贷款逾期预测-赛后总结
热门文章
- 商品审核网页界面_商品模块数据库表解析(二)
- android oom 检测工具,Android中UI检测、内存泄露、OOM、等优化处理
- 风控建模 python 知乎_风控建模基本要求及面试问题小结
- shell脚本如何实现goto_linux通过shell脚本实现对apache服务的监控
- 从零开始学习docker(十一)介绍Docker Compose yml文件介绍
- 8个字典常用的内置函数,一次性给你总结了!
- 今年数据分析到底有多火?全网跪求优质资源!
- 开源神器!答应我,别再用 abc 做变量名了好么!
- widget模式弄不出来_【春天文化】互联网时代的教育模式培养精英
- informix clob转oracle 乱码_Oracle 视图-序列-权限-表-事务