- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章MySQL的id关联和索引使用的实际优化案例由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
昨晚收到客服MM电话,一用户反馈数据库响应非常慢,手机收到load异常报警,登上主机后发现大量sql执行非常慢,有的执行时间超过了10s 优化点一:
1
|
SELECT
*
FROM
`sitevipdb`.`game_shares_buy_list`
WHERE
price>='2.00′
ORDER
BY
tran_id
DESC
LIMIT 10;
|
表结构为:
1
2
3
4
5
6
|
CREATE
TABLE
`game_shares_buy_list` (
`tran_id`
int
(10) unsigned
NOT
NULL
AUTO_INCREMENT,
`………..'
PRIMARY
KEY
(`tran_id`),
KEY
`ind_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=3144200
DEFAULT
CHARSET=utf8;
|
执行计划:
1
2
3
4
5
6
7
|
root@127.0.0.1 : sitevipdb 09:10:22> explain SELECT * FROM `sitevipdb`.`game_shares_buy_list` WHERE price>='2.00′ ORDER BY tran_id DESC LIMIT 10;
+—-+————-+———————-+——-+—————+———+———+——+——+————-+
|
id
| select_type | table |
type
| possible_keys | key | key_len | ref | rows | Extra |
+—-+————-+———————-+——-+—————+———+———+——+——+————-+
| 1 | SIMPLE | game_shares_buy_list | index | NULL | PRIMARY | 4 | NULL | 10 | Using where |
+—-+————-+———————-+——-+—————+———+———+——+——+————-+
1 row
in
set
(0.00 sec)
|
分析该sql的执行计划,由于tran_id是表的主键,所以查询根据主键降序顺序扫描,这样就可以不用排序, 然后在过滤条件price>2.00的记录,看上去这个执行计划貌似非常好,如果查询扫描到了满足条件的10条记录,就会停止扫描; 但是这里有个问题,如果表中有大量的记录是不符合2.00的,意味查询就需要扫描非常多的记录,才能找到符合条件的10条:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
root@127.0.0.1 : sitevipdb 09:17:23>
select
price,count(*) as cnt from `game_shares_buy_list` group by price order by cnt desc limit 10;
+——-+——-+
| price | cnt |
+——-+——-+
| 1.75 | 39101 |
| 1.68 | 38477 |
| 1.71 | 34869 |
| 1.66 | 34849 |
| 1.72 | 34718 |
| 1.70 | 33996 |
| 1.76 | 32527 |
| 1.69 | 27189 |
| 1.61 | 25694 |
| 1.25 | 25450 |
|
可以看到表中有大量的记录不是2.00的,所以这个时候不能在根据主键顺序扫描,在过滤记录; 那么是否需要在price建立一个索引:
1
2
3
4
5
6
7
8
9
10
11
|
root@127.0.0.1 : sitevipdb 09:09:01>
select
count(*) from `game_shares_buy_list` where price>'2′;
+———-+
| count(*) |
+———-+
| 4087 |
+———-+
root@127.0.0.1 : sitevipdb 09:17:31>
select
count(*) from `game_shares_buy_list` ;
+———-+
| count(*) |
+———-+
| 1572100 |
|
从上面price的数据分布可以看出,price的分布相对还是比较集中的,如果在price建立索引,mysql也有可能认为由于需要回表的记录过多, 同时需要额外的排序,而不选择在price上的索引:
1
2
|
root@127.0.0.1 : sitevipdb 09:24:53>
alter
table
game_shares_buy_list
add
index
ind_game_shares_buy_list_price(price);
Query OK, 0
rows
affected (5.79 sec)
|
可以看到优化器虽然注意到了我们新加的索引,但是最终还是选择了primary来扫描; 所以这个时候我们加上去的索引没有产生效果,数据库负载依然很高,如果强制走price上的索引,效果会这样:
1
2
3
4
5
6
7
|
root@127.0.0.1 : sitevipdb 09:35:38> SELECT * FROM `sitevipdb`.`game_shares_buy_list` WHERE price>='2.0′ ORDER BY tran_id DESC LIMIT 10;
。。。。。
10 rows
in
set
(7.06 sec)
root@127.0.0.1 : sitevipdb 09:36:00> SELECT * FROM `sitevipdb`.`game_shares_buy_list` force index(ind_game_shares_buy_list_price) WHERE price>='2.0′ ORDER BY tran_id DESC LIMIT 10;
。。。。
10 rows
in
set
(1.01 sec)
|
可以看到如果强制走索引,时间已经明显下降了,但是还是有些慢,能不能在快一点?其实我们需要扫描的记录只有10条,但查询在取得这10条记录的时候需要扫描大量无效的记录 。
怎么降低这个数据:其实只要改写一下sql就可以,我们先从索引中得到满足条件的10个id,在回表进行关联:
1
2
3
4
|
root@127.0.0.1 : sitevipdb 09:44:45>
select
*
from
game_shares_buy_list t1,
-> (
SELECT
tran_id
FROM
sitevipdb.game_shares_buy_list
WHERE
price>='2.0′
ORDER
BY
tran_id
DESC
LIMIT 10) t2
->
where
t1.tran_id=t2.tran_id;
10
rows
in
set
(0.00 sec)
|
可以看到执行时间已经不在秒级别了,和客户电话沟通后,很愿意这样改写sql.
—这里看到是order by tran_id是要额外排序的,索引也可以这样来建立消除排序(tran_id,price)这样可以消除排序,同时可以利用order by desc/asc +limit M,N的优化.
优化点二:
1
2
3
4
5
6
7
8
|
CREATE
TABLE
`game_session` (
`session_id`
varchar
(255)
CHARACTER
SET
utf8
COLLATE
utf8_bin
NOT
NULL
DEFAULT
,
`session_expires`
int
(10) unsigned
NOT
NULL
DEFAULT
'0′,
`client_ip`
varchar
(16)
DEFAULT
NULL
,
`session_data` text,
…………………….
PRIMARY
KEY
(`session_id`)
) ENGINE=InnoDB
DEFAULT
CHARSET=utf8;
|
查询为select `session_data`, `session_expires` from `game_session` where session_id='xxx'出现大量等待情况 同时该表的insert,也有等待的现象; 可以看到这个表结构设计是有些问题的,咨询了客户后,可以改为下面结构:
1
2
3
4
5
6
7
8
9
|
CREATE
TABLE
`game_session` (
id
int
auto_increment,
`session_id`
varchar
(30)
CHARACTER
SET
utf8
COLLATE
utf8_bin
NOT
NULL
DEFAULT
,
`session_expires`
int
(10) unsigned
NOT
NULL
DEFAULT
'0′,
`client_ip`
varchar
(16)
DEFAULT
NULL
,
`session_data`
varchar
(200),
PRIMARY
KEY
(id),
key
ind_session_id(session_id,session_data, session_expires)
) ENGINE=InnoDB
DEFAULT
CHARSET=utf8;
|
小结:
最后此篇关于MySQL的id关联和索引使用的实际优化案例的文章就讲到这里了,如果你想了解更多关于MySQL的id关联和索引使用的实际优化案例的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
出现在 python 2.7.8 中。 3.4.1 不会发生这种情况。 示例: >>> id(id) 140117478913736 >>> id(id) 140117478913736 >>> id
好吧,我对动态创建的控件的 ID 很困惑。 Public Class TestClass Inherits Panel Implements INamingContainer
我收到下面的错误,说有堆栈溢出。发生这种情况是因为带有 IN (id, id, id...id) 的 SQL 语句有大量参数。有没有什么办法解决这一问题?这是在我使用 Eclipse 的本地环境中发生
为什么 CPython(不知道其他 Python 实现)有以下行为? tuple1 = () tuple2 = ()
为什么 CPython(对其他 Python 实现一无所知)有以下行为? tuple1 = () tuple2 = ()
非常简单的问题:当我有一个持久对象时,它通常有一个名为 ID 的属性(对于抽象类)。 那么..命名约定是ID还是Id? 例如。 public int ID { get; set; } 或 public
知道为什么我会收到此错误,我已经尝试了所有命名约定(小写/大写) 我正在使用 Vaadin,这是我的代码片段: public class Usercontainer extends BeanI
为什么 CPython(不知道其他 Python 实现)有以下行为? tuple1 = () tuple2 = ()
我需要改变表的所有主键 UPDATE TODO SET id = id + 1 但我做不到(Demo 来自 Ahmad Al-Mutawa 的回答)描述了原因。主键不能这样改。 我也不能根据这是 sq
我正在尝试列出与用户相关的讨论列表。 想象一下,如果你愿意的话: posts -------------------------------------------------------------
我有一个表,其中包含一些具有自己的 ID 和共享 SKU key 的文章。我尝试使用左连接进行查询,并使用组结果获取从查询返回的所有 id。 我的数据结构是这样的: id - name -
在下表People中: id name 1 James 2 Yun 3 Ethan 如果我想找到最大 ID,我可以运行此查询 select max(id) id from People; 结果是
我正在产品页面上创建评论模块,其中显示垃圾评论选项,并显示 onclick 显示和隐藏弹出窗口。现在它在单个评论中工作正常但是当评论是两个时它同时打开两个因为类是相同的。现在这就是为什么我想要获取父
根据 REST 哲学,PUT操作应该(取自维基百科): PUT http://example.com/resources/142 Update the address member of the co
我想知道如何在使用 PHP 或 JavaScript 进行身份验证后从 Google Analytics 获取 Property Id、View Id 和 Account Id?因为我希望能够将它们存
我想使用所选按钮的 ID 进行删除。但我不知道如何从中获取/获取 id。我尝试了 this.id 但不起作用。 这是我创建按钮的地方: var deleteEmployer= document.cre
我有一个具有以下结构的表“表” ID LinkedWith 12 13 13 12 14 13 15 14 16
请不要在未阅读问题的情况下将问题标记为重复。我确实发布了一个类似的问题,但 STACKOVERFLOW 社区成员要求我单独重新发布修改后的问题,因为考虑到一个小而微妙的修改,解决方案要复杂得多。 假设
在 Android Studio 中,我创建了一个 Person.java 类。我使用Generate 创建了getter 和setter 以及构造函数。 这是我的 Person.java 类: pu
如何在 jQuery 中制作这样的东西: //这是显示的主体 ID //当我悬停 #hover-id 时,我希望 #principal-id 消失并更改 。但是当我将光标放在 #this-id 上时
我是一名优秀的程序员,十分优秀!