Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
L
lesson plan
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Bugzilla
Bugzilla
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
王雷
lesson plan
Commits
44941b0e
Commit
44941b0e
authored
Jan 24, 2019
by
王雷
😹
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update (SQL)优化分析与方法.md
parent
3688aea7
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
53 additions
and
53 deletions
+53
-53
(SQL)优化分析与方法.md
(SQL)优化分析与方法.md
+53
-53
No files found.
(SQL)优化分析与方法.md
View file @
44941b0e
...
@@ -101,69 +101,69 @@ limit
...
@@ -101,69 +101,69 @@ limit
6.
条件类型,在执行查询时,作为变量的条件要尽可能的与要比对的数据列类型一致,减少数据库引擎转换数据类型的时间;
6.
条件类型,在执行查询时,作为变量的条件要尽可能的与要比对的数据列类型一致,减少数据库引擎转换数据类型的时间;
7.
如果要参与比对的条件需要用到函数,则尽量避免在数据列上使用,这样会造成索引失效,而形成全表扫描,增加数据量;
7.
如果要参与比对的条件需要用到函数,则尽量避免在数据列上使用,这样会造成索引失效,而形成全表扫描,增加数据量;
8.
如果查询条件中对同一个数据列有多个选项,不要使用 or 进行条件关联,而是使用 in;
8.
如果查询条件中对同一个数据列有多个选项,不要使用 or 进行条件关联,而是使用 in;
9.
如果查询条件中是一个变量可能符合多个数据列,可以将 in 反过来写,如,订单表中,想要查找
**未交费**
或
**未开票**
或
**未发货**
的数据,则条件可以写为
***where 'N' in (pay_status, invoice_status, send_status)**
*
;
9.
如果查询条件中是一个变量可能符合多个数据列,可以将 in 反过来写,如,订单表中,想要查找
**未交费**
或
**未开票**
或
**未发货**
的数据,则条件可以写为
```where 'N' in (pay_status, invoice_status, send_status)```
;
10.
如果查询条件包含较多的 or,可以使用 union all 来分解为多个 and 条件的 sql,避免因为使用 or 关系造成索引失效;
10.
如果查询条件包含较多的 or,可以使用 union all 来分解为多个 and 条件的 sql,避免因为使用 or 关系造成索引失效;
11.
避免不必要的分组和排序;
11.
避免不必要的分组和排序;
12.
如非
比较
,减少 like 的使用,like 比较在大部分情况下无法利用到索引;
12.
如非
必要
,减少 like 的使用,like 比较在大部分情况下无法利用到索引;
13.
从我了解到的资料看,MySQL 在解析 from 中的表和 Where 中的条件时基本都是采用自
做向右的方式进行处理,因此我们再
写跨表查询和多条件查询时,要尽量将可以大量过滤数据的条件写在前面,将可以利用索引的条件写在前面;
13.
从我了解到的资料看,MySQL 在解析 from 中的表和 Where 中的条件时基本都是采用自
左向右的方式进行处理,因此我们在
写跨表查询和多条件查询时,要尽量将可以大量过滤数据的条件写在前面,将可以利用索引的条件写在前面;
14.
在使用条件时,尽量减少 not、
<>
这样的比较方式;
14.
在使用条件时,尽量减少 not、
<>
这样的比较方式;
15.
能使用 between 时,尽量别拆成
多个 or
条件;
15.
能使用 between 时,尽量别拆成
in
条件;
16.
能使用去重方式获取数据,就不要使用 group by 进行分组;
16.
能使用去重方式获取数据,就不要使用 group by 进行分组;
17.
合理利用 limit,减少一次性传输大量数据的可能;
17.
合理利用 limit,减少一次性传输大量数据的可能;
18.
合理利用游标技术,减少反复查询;
18.
合理利用游标技术,减少反复查询;
#### 五、举个栗子 ☺
#### 五、举个栗子 ☺
  
下面,我们
拉出在
**2019年1月**
造成大规模线上问题
的 SQL 来具体说明优化步骤。
  
下面,我们
揪出在
**2019年1月**
造成
**大规模线上问题**
的 SQL 来具体说明优化步骤。
```
sql
```
sql
-- 这个就是造成数据库 CPU 超负荷以至于停止对外服务的罪魁祸首
-- 这个就是造成数据库 CPU 超负荷以至于停止对外服务的罪魁祸首
SELECT
select
ss
.
djxh
djxh
,
ss
.
djxh
djxh
,
ci
.
ID
cid
,
ci
.
id
cid
,
ci
.
E_ID
eid
,
ci
.
e_id
eid
,
ss
.
ID
sbid
,
ss
.
id
sbid
,
ci
.
SHXYDM
shxydm
,
ci
.
shxydm
shxydm
,
ci
.
CUSTOMER_NAME
customer_name
,
ci
.
customer_name
customer_name
,
db
.
BBLX_MC
zsxm_mc
,
db
.
bblx_mc
zsxm_mc
,
CASE
ss
.
TB_BZ
WHEN
'Y'
THEN
'已同步'
ELSE
(
CASE
ss
.
SBZT
WHEN
'Y'
THEN
'已申报'
ELSE
'未申报'
END
)
END
AS
sbzt
,
case
ss
.
tb_bz
when
'Y'
then
'已同步'
else
(
case
ss
.
sbzt
when
'Y'
then
'已申报'
else
'未申报'
end
)
end
as
sbzt
,
ss
.
SBRQ
sbrq
,
ss
.
sbrq
sbrq
,
ss
.
YBTSE
ybtse
,
ss
.
ybtse
ybtse
,
CASE
ss
.
JKZT
WHEN
'Y'
THEN
'已缴款'
ELSE
'未缴款'
END
AS
jkzt
,
case
ss
.
jkzt
when
'Y'
then
'已缴款'
else
'未缴款'
end
as
jkzt
,
ss
.
JKRQ
jkrq
,
ss
.
jkrq
jkrq
,
ss
.
SSSQ_Q
sssq_q
,
ss
.
sssq_q
sssq_q
,
ss
.
SSSQ_Z
sssq_z
,
ss
.
sssq_z
sssq_z
,
ss
.
ZSXM_DM
zsxm_dm
,
ss
.
zsxm_dm
zsxm_dm
,
ss
.
BBLX_DM
bblx_dm
,
ss
.
bblx_dm
bblx_dm
,
ei
.
REAL_NAME
NAME
,
ei
.
real_name
name
,
ss
.
SWJGMC
swjgmc
,
ss
.
swjgmc
swjgmc
,
ss
.
SWJGJC
swjgjc
,
ss
.
swjgjc
swjgjc
,
ss
.
NSRSBQ
nsrsbq
ss
.
nsrsbq
nsrsbq
FROM
agency_tax
.
sb_sbxx
ss
from
agency_tax
.
sb_sbxx
ss
LEFT
JOIN
`customer_info`
ci
ON
ci
.
ID
=
ss
.
C_ID
left
join
`customer_info`
ci
on
ci
.
id
=
ss
.
c_id
LEFT
JOIN
agency_tax
.
dm_bblx
db
ON
db
.
BBLX_DM
=
ss
.
BBLX_DM
left
join
agency_tax
.
dm_bblx
db
on
db
.
bblx_dm
=
ss
.
bblx_dm
LEFT
JOIN
employee_info
ei
ON
ei
.
id
=
ci
.
SERVICE_TAX_ID
left
join
employee_info
ei
on
ei
.
id
=
ci
.
service_tax_id
LEFT
JOIN
(
left
join
(
SELECT
b
.
num
,
sbxx
.
SB_ID
,
sbxx
.
BB_DM
select
b
.
num
,
sbxx
.
sb_id
,
sbxx
.
bb_dm
FROM
agency_tax
.
sb_sbxx_bbmx
sbxx
from
agency_tax
.
sb_sbxx_bbmx
sbxx
LEFT
JOIN
(
left
join
(
SELECT
COUNT
(
*
)
num
,
bbmx
.
SB_ID
sbI
d
select
count
(
*
)
num
,
bbmx
.
sb_id
sbi
d
FROM
agency_tax
.
sb_sbxx_bbmx
bbmx
from
agency_tax
.
sb_sbxx_bbmx
bbmx
WHERE
bbmx
.
STATE
=
'Y'
where
bbmx
.
state
=
'Y'
GROUP
BY
bbmx
.
SB_ID
group
by
bbmx
.
sb_id
)
b
ON
b
.
sbId
=
sbxx
.
SB_ID
)
b
on
b
.
sbid
=
sbxx
.
sb_id
WHERE
sbxx
.
STATE
=
'Y'
where
sbxx
.
state
=
'Y'
GROUP
BY
sbxx
.
ID
group
by
sbxx
.
id
)
a
ON
ss
.
ID
=
a
.
SB_ID
)
a
on
ss
.
id
=
a
.
sb_id
WHERE
ss
.
state
=
'Y'
where
ss
.
state
=
'Y'
AND
a
.
num
>
0
and
a
.
num
>
0
AND
ci
.
CUSTOMER_NAME
LIKE
'%柏%'
and
ci
.
customer_name
like
'%柏%'
AND
(
ss
.
SBZT
=
'Y'
OR
ss
.
BBLX_DM
=
'10411'
OR
ss
.
TB_BZ
=
'Y'
)
and
(
ss
.
sbzt
=
'Y'
or
ss
.
bblx_dm
=
'10411'
or
ss
.
tb_bz
=
'Y'
)
AND
ci
.
SERVICE_TAX_ID
=
696
and
ci
.
service_tax_id
=
696
GROUP
BY
ss
.
ID
group
by
ss
.
id
ORDER
BY
ss
.
SSSQ_Z
DESC
,
ss
.
C_ID
,
ss
.
ID
order
by
ss
.
sssq_z
desc
,
ss
.
c_id
,
ss
.
id
LIMIT
15
limit
15
```
```
  
这个 sql 的业务是查询符合条件税种申报、缴款情况,并返给用户查看,在发生问题的时刻,这个 sql 涉及的数据表
数据长度
如下表:
  
这个 sql 的业务是查询符合条件税种申报、缴款情况,并返给用户查看,在发生问题的时刻,这个 sql 涉及的数据表
行数
如下表:
| 序号 | 数据表名称 | 数据行数 |
| 序号 | 数据表名称 | 数据行数 |
|---|---|---|
|---|---|---|
...
@@ -180,7 +180,7 @@ LIMIT 15
...
@@ -180,7 +180,7 @@ LIMIT 15
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | extra |
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | extra |
|---|---|---|---|---|---|---|---|---|---|
|---|---|---|---|---|---|---|---|---|---|
| 1 | PRIMARY |
<derived2>
| ALL | | | | | 53801 | Using where; Using temporary; Using filesort |
| 1 | PRIMARY |
<derived2>
| ALL | | | | |
10
53801 | Using where; Using temporary; Using filesort |
| 1 | PRIMARY | ss | eq_ref | PRIMARY,IDX_SB_SBXX_CID,IDX_SB_SBXX_CID_ZSXM,IDX_SB_SBXX_CID_ZSXM_SQ,IDX_SB_SBXX_CID_ZSXM_BBLX_SQ,IDX_SB_SBXX_SQ_STATE | PRIMARY | 4 | a.SB_ID | 1 | Using where |
| 1 | PRIMARY | ss | eq_ref | PRIMARY,IDX_SB_SBXX_CID,IDX_SB_SBXX_CID_ZSXM,IDX_SB_SBXX_CID_ZSXM_SQ,IDX_SB_SBXX_CID_ZSXM_BBLX_SQ,IDX_SB_SBXX_SQ_STATE | PRIMARY | 4 | a.SB_ID | 1 | Using where |
| 1 | PRIMARY | db | eq_ref | PRIMARY | PRIMARY | 30 | agency_tax.ss.BBLX_DM | 1 | |
| 1 | PRIMARY | db | eq_ref | PRIMARY | PRIMARY | 30 | agency_tax.ss.BBLX_DM | 1 | |
| 1 | PRIMARY | ci | eq_ref | PRIMARY | PRIMARY | 4 | agency_tax.ss.C_ID | 1 | Using where |
| 1 | PRIMARY | ci | eq_ref | PRIMARY | PRIMARY | 4 | agency_tax.ss.C_ID | 1 | Using where |
...
@@ -256,11 +256,11 @@ limit 15
...
@@ -256,11 +256,11 @@ limit 15
```
```
  
对优化前和优化后的 SQL 分别执行,时间分别为 2s 和 300ms(多次平均),基本可以认为 SQL 完成了优化;
  
对优化前和优化后的 SQL 分别执行,时间分别为 2s 和 300ms(多次平均),基本可以认为 SQL 完成了优化;
  
我们再次执行查询计划,发现仍然存在一个
一个
全表扫描,customer_info 表;
  
我们再次执行查询计划,发现仍然存在一个全表扫描,customer_info 表;
  
纵观 SQL,我们可以看到 customer_info 除了提供结果数据外,还提供了一个筛选条件 service_tax_id,而通过分析表结构发现,service_tax_id 列缺少索引,并且该列可以过滤大量数据,因此可以考虑增加索引;
  
纵观 SQL,我们可以看到 customer_info 除了提供结果数据外,还提供了一个筛选条件 service_tax_id,而通过分析表结构发现,service_tax_id 列缺少索引,并且该列可以过滤大量数据,因此可以考虑增加索引;
  
增加索引后,再次执行优化后的 SQL,可以看到执行时间已经降低到 15ms(平均多次),至此,我们可以
任务
,本次 SQL 优化完成。
  
增加索引后,再次执行优化后的 SQL,可以看到执行时间已经降低到 15ms(平均多次),至此,我们可以
认为
,本次 SQL 优化完成。
#### 五、总结
#### 五、总结
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment