MySQL-业务优化——说的就是变

前言

通过上次发布的业务优化不是一步到位的有不少网友问我许多关于业务优化和Web方面的问题。在这里表示感谢和支持。在期间有些回答不到位的还请谅解,并且个人经验有限。

新的问题

其中有一位网友说看了文章,并且实践在自己的项目上,效果还是不错的。但是有一个场景,表现的效果不是很好,或者说效果基本没有什么改变。

在相互的沟通了一下,了解他们的场景,以及相关表结构。之后给予了相关建议,听说效果还不还行。就是让开发有些不满意 ^_^。

题外话:其实可以请开发吃顿饭,增进感情 ^_^。

下面我使用演示的方式将这个场景进行分析和优化(该场景并非网友的)。

场景讲解

每个用户都可以查看商品的列表,在商品列表点击商品描述的时候,会弹出一个窗口并显示。详细的商品介绍的信息。表结构如下:

<br />
CREATE TABLE goods(<br />
goods_id INT NOT NULL AUTO_INCREMENT COMMENT ‘主键ID’,<br />
name VARCHAR(30) NOT NULL DEFAULT ” COMMENT ‘商品名称’,<br />
descript VARCHAR(2000) NOT NULL DEFAULT ” COMMENT ‘商品描述’,<br />
PRIMARY KEY(goods_id)<br />
) COMMENT = ‘商品表’;
1
2
3
4
5
6
(
,
,
,
)
;

刚开始的时候查询如下:

<br />
SELECT goods_id, name, descript FROM goods LIMIT 0, 50;
1
;

通过执行上面SQL一次新就找出了50条数据,初步算了一下一次性需要传输的数据量大概 100K,可想而知当多人同时访问的时候,有限的带宽只能接受较少的请求和并发。

改进的查询如下

瞄过业务不是一步到位的的网友估计会把这个请求拆成两个请求,以至于达到优化的目的。如下:

第一个请求:只获取商品的基本信息(快)

<br />
SELECT goods_id, name FROM goods LIMIT 0, 50;
1
;

第二个异步请求:通过获取的goods_id集合来获取商品的描述descript

<br />
SELECT goods_id, descript FROM goods WHERE goods_id IN(上面获得的goods_id集合)
1
)

确实是按之前的优化方法进行优化了,可以为啥性能还是没改善呢?

慢的原因

从上面可以看出,第一个查询确实能很快的放回和传输数据,这是毋庸置疑的。

我们再来看看第二个请求,它查出的数据大小其实和之前一次性查出的数据大小其实没有很大的差别。问题就在这里了。

如果是指一个人在查询,可以感觉确实有快很多。因为第一个请求的数据会很快的展现在前端,第二个异步请求的慢其实让用户感觉不到。

但是如果人多了,并发请求高了。异步请求多了,那数据库不断的获取传输数据。这样数据库不断的在IO上,从而影响了并发。所以也会感觉慢。这就相当于优化和没优化是一样的。

总的原因就是实时加载了哪些看上去实时,实际不需要实时加载的数据descript

#### 分析客户和产品的需求

1、大多数客户并不需要每次都查看所有的商品的描述,只想了解个别自己感兴趣的商品描述。

Tips:如果在开发或产品上得不到这样的答案,可以自己去范围日志里面分析比例。访问商品列表和访问商品详情的请求比例。

2、根据客户和产品的需求,他们需要一眼就能大概了解每个商品的大致描述。

解决思路

知道了慢的原因,并且了解了客户的基本需求。解决办法就是对描述数据进行拆分并且限制请求

将第二个异步请求,转化为被动的异步请求。也就是说我们在用户点击查看详情的时候在去一个个异步的去加载商品的详情信息。

将一张表拆分成两张表,如下:

<br />
— 主商品信息表<br />
CREATE TABLE goods(<br />
goods_id INT NOT NULL AUTO_INCREMENT COMMENT ‘主键ID’,<br />
name VARCHAR(30) NOT NULL DEFAULT ” COMMENT ‘商品名称’,<br />
introduce VARCHAR(30) NOT NULL DEFAULT ” COMMENT ‘商品简介’,<br />
PRIMARY KEY(goods_id)<br />
) COMMENT = ‘商品表’;<br />
— 商品描述表<br />
CREATE TABLE goods_descript(<br />
goods_descript_id INT NOT NULL AUTO_INCREMENT COMMENT ‘主键ID’,<br />
goods_id INT NOT NULL COMMENT ‘商品ID’,<br />
descript VARCHAR(2000) NOT NULL DEFAULT ” COMMENT ‘商品描述’,<br />
PRIMARY KEY(goods_descript_id),<br />
UNIQUE KEY udx$goods_id(goods_id)<br />
) COMMENT = ‘商品描述表’;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
主商品信息表
(
,
,
,
)
;
商品描述表
(
,
,
,
,
)
;

上面我们将商品的描述信息拆分到了另外一个表中。并且在主信息表goods中添加一个商品简介字段introduce

用户在保存信息的时候可以编写一些商品的一些简要介绍,或者从商品描述中截取一部分信息到商品简介中。

最后的体验

通过上面的改造后我们的SQL很简单。

第一步:用户查询商品列表只需要个简单的SQL就完成了,如下:

<br />
SELECT goods_id, name, introduce FROM goods LIMIT 0, 50;
1
;

第二步:有需要查询商品描述的用户也只需要一个简单的SQL,如下:

<br />
SELECT goods_id, descript FROM goods WHERE goods_id IN(上面获得的goods_id)
1
)

Tips:第二步是被动的,当用户点击的时候才进行异步加载商品信息。并只加载当前点击的商品的描述

要被开发骂了

其实我们还可以进一步优化,就是如果对已经异步加载的商品描述,使用前端技术保存在页面中并隐藏起来。这样如果用户再次点击的时候,只需要获取前端页面隐藏的商品描述进行展现,并不需要再次请求。这样就减小了后端的压力了。

上面的做法就需要增加开发人员的工作量了。

Tips:一般前端隐藏技术可以使用 <input type="hidden" value="商品描述隐藏在这里">

祝大家工作愉快。


数据运维技术 » MySQL-业务优化——说的就是变