mysql迁移之后读取速度变慢_如何解决数据库迁移之后变慢的问题
阿里云關(guān)系型數(shù)據(jù)庫(kù)服務(wù)(Relational
Database Service,簡(jiǎn)稱(chēng)RDS)是一種即開(kāi)即用、穩(wěn)定可靠、可彈性伸縮的在線數(shù)據(jù)庫(kù)服務(wù)。具有多重安全防護(hù)措施和完善的性能監(jiān)控體系,并提供專(zhuān)業(yè)的數(shù)據(jù)庫(kù)備份、恢復(fù)及優(yōu)化方案,使您能專(zhuān)注于應(yīng)用開(kāi)發(fā)和業(yè)務(wù)發(fā)展。
使用阿里云關(guān)系數(shù)據(jù)庫(kù)RDS時(shí),經(jīng)常聽(tīng)到很抱怨,為什么我的RDS 突然變慢了?相信不少客戶(hù)在使用RDS 中經(jīng)常遇到的頭疼問(wèn)題。像這樣情況的發(fā)生,可能是由于用戶(hù)操作不當(dāng)而產(chǎn)生,為了重拾用戶(hù)對(duì)我們RDS的使用信心。 接下來(lái)我們通過(guò)真實(shí)案例來(lái)分析一下用戶(hù)在使用RDS 中變慢的原因:
案例一:
用戶(hù)從PGSQL遷移到RDS后,發(fā)現(xiàn)RDS變慢了。
問(wèn)題描述:用戶(hù)的數(shù)據(jù)庫(kù)(pgsql)遷移到RDS(mysql)后,發(fā)現(xiàn)相同的一條sql 語(yǔ)句,數(shù)據(jù)量百萬(wàn)級(jí)左右,在原來(lái)postgreSQL 中執(zhí)行大概是0.015s,而在RDS 下直接運(yùn)行是6分20秒左右,執(zhí)行非常的慢,已經(jīng)嚴(yán)重的影響用戶(hù)使用RDS的信心。而實(shí)際上,這個(gè)問(wèn)題來(lái)自于異構(gòu)數(shù)據(jù)庫(kù)的遷移,由于不同數(shù)據(jù)庫(kù)引擎使用的優(yōu)化算法不同因此同一個(gè)SQL的性能表現(xiàn)會(huì)存在差異,能過(guò)以下操作我們可以進(jìn)行分析并解決。
可能原因:為什么在用戶(hù)的數(shù)據(jù)庫(kù)上執(zhí)行只需要0.015s,而到RDS 后變?yōu)榱?分20s?根據(jù)經(jīng)驗(yàn),很有可能是SQL 的執(zhí)行計(jì)劃改變了,而導(dǎo)致執(zhí)行時(shí)間劇增。
問(wèn)題排查:通過(guò)explain 查看sql 的執(zhí)行計(jì)劃,一步一步進(jìn)行優(yōu)化。
通過(guò)分析,可以從執(zhí)行計(jì)劃上分析b 表做了一個(gè)全表掃描(執(zhí)行計(jì)劃的最后一行),查看b 表中tid 并無(wú)索引,所以我們這里可以進(jìn)行優(yōu)化,來(lái)減少查詢(xún)過(guò)程中關(guān)聯(lián)的行數(shù),從而達(dá)到優(yōu)化:
我們可以看到執(zhí)行計(jì)劃中的rows 已經(jīng)從452變?yōu)榱?(執(zhí)行計(jì)劃的最后一行),
由于mysql 表關(guān)聯(lián)只有nest loop join 這種算法,所以我們可以估算一下這里的優(yōu)化:
原始執(zhí)行一:1055789*1*1*1*1*452
掃描的行數(shù)
新執(zhí)行計(jì)劃二:1055789*1*1*1*1*2
掃描的行數(shù)
執(zhí)行時(shí)間:
我們看到執(zhí)行時(shí)間已經(jīng)由原來(lái)的6分20秒下降到了10秒,我們繼續(xù)優(yōu)化;
可以看到該sql 的結(jié)果集只有8行,但掃描的行數(shù)卻是非常之大的(1055789*1*1*1*1*2),在優(yōu)化sql 的非常關(guān)鍵的一點(diǎn)就是優(yōu)化sql 的執(zhí)行路程,t=s/v;如果我們能夠優(yōu)化S,那么速度肯定會(huì)一下子提上來(lái);那么我們?cè)诳纯磗ql 中最后的一句:
-> WHERE EXISTS
-> (SELECT 1 FROM xxxx_test5 b WHERE
a.tid = b.tid);
sql 查詢(xún)中是要查詢(xún)出每筆訂單的詳細(xì)信息而不得不關(guān)聯(lián)其他一些表,但是最后的一個(gè)exist 限定了我們最后結(jié)果的范圍,在看看xxxx_test5
這張表有多大:
mysql> SELECT COUNT(*) FROM xxxx_test5;
+----------+
| COUNT(*) |
+----------+
| 403 |
+----------+
1 ROW IN SET (0.00 sec)
mysql> SELECT COUNT(*) FROM xxxx_test5 b
,xxxx_test a WHERE
a.tid = b.tid ;
+----------+
| COUNT(*) |
+----------+
| 8 |
+----------+
1 ROW IN SET (0.42 sec)
兩張表關(guān)聯(lián)后只有8行記錄,如果我們將訂單表xxxx_test 和限定表先做關(guān)聯(lián),在和其他的一些訂單信息表做連接,將會(huì)極大減小關(guān)聯(lián)的行數(shù);在進(jìn)一步改寫(xiě)sql:
分析執(zhí)行計(jì)劃,我們發(fā)現(xiàn)限定表xxxx_test5做了驅(qū)動(dòng)表,驅(qū)動(dòng)表的變化才是導(dǎo)致問(wèn)題的最根本原因,掃描的行數(shù):452*1*1*1*1; 這個(gè)時(shí)候sql 的執(zhí)行速度將非常快:
Mysql-->;
SELECT a.oi.............
........省去結(jié)果
8 ROWS IN SET (0.13 sec)
總結(jié):由于環(huán)境遷移,導(dǎo)致sql執(zhí)行計(jì)劃改變,這就是RDS變慢的最終原因。
案例二:
用戶(hù)使用RDS(mssql),經(jīng)常出現(xiàn)連接超時(shí)報(bào)錯(cuò)。
問(wèn)題描述:?使用mssql rds 時(shí)不時(shí)報(bào)錯(cuò)如下,詢(xún)問(wèn)是否是連接超過(guò)限制導(dǎo)致的?
A network-related orinstance-specific error
occurred while establishing a connection toSQL Server. The server was not found
or was not accessible. Verifythat the instance name is correct and that SQL
Server is configured toallow remote connections. (provider: SQL Network
Interfaces, error:26 – Error Locating
Server/Instance Specified)
可能原因:可能用戶(hù)的應(yīng)用程序設(shè)計(jì)的不是很好,導(dǎo)致數(shù)據(jù)庫(kù)鎖征用較多;或由于沒(méi)有建立適當(dāng)?shù)乃饕?#xff0c;導(dǎo)致全表掃描,造成數(shù)據(jù)庫(kù)等待;
問(wèn)題排查:通過(guò)查看數(shù)據(jù)庫(kù)的監(jiān)控指標(biāo),發(fā)現(xiàn)在某個(gè)時(shí)間段有大量的全表掃描,同時(shí)數(shù)據(jù)庫(kù)的鎖爭(zhēng)超時(shí),會(huì)話(huà)數(shù)明顯增加。
可以看到在15:00的時(shí)候有大量的全表掃描,出現(xiàn)了較多的鎖超時(shí)的情況,同時(shí)這個(gè)時(shí)候也有大量的會(huì)話(huà)在數(shù)據(jù)庫(kù)中,而這個(gè)時(shí)間恰好也是用戶(hù)報(bào)出錯(cuò)誤的時(shí)間,在進(jìn)一步排查,用戶(hù)的SQL,通過(guò)查看mssql 內(nèi)部的一些視圖,來(lái)找到對(duì)應(yīng)消耗資源top 5的sql,發(fā)現(xiàn)用戶(hù)頻繁的查詢(xún)一個(gè)視圖,在視圖中有多表連接,但在這些表連接中的字段上沒(méi)有添加索引,導(dǎo)致了全表掃描,用戶(hù)視圖如下:
CREATE VIEW [dbo].[Vi_xxx]
AS
SELECT ..........
..........
FROM dbo.xxxx_test6 INNER JOIN
dbo.xxxx_test1 ON dbo.xxxx_test5.docID =
dbo.xxxx_test1.docID
INNER JOIN
dbo.xxxx_test2 ON dbo.xxxx_test5.typeID =
dbo.xxxx_test2.typeID
INNER JOIN
dbo.xxxx_test3 ON dbo.xxxx_test5.docID =
dbo.xxxx_test3.docID
INNER JOIN
dbo.xxxx_test4 ON dbo.xxxx_test5.categoryID
=
dbo.xxxx_test4.categoryID
WHERE (dbo.xxxx_test5.isDelete = 0)
通過(guò)查看執(zhí)行計(jì)劃,發(fā)現(xiàn)表上面很多的關(guān)聯(lián)字段沒(méi)有建立索引,導(dǎo)致全表掃描執(zhí)行計(jì)劃如下(有很多的table scan):
總結(jié):用戶(hù)頻繁的查詢(xún)一個(gè)視圖,而該視圖中表的關(guān)聯(lián)字段上沒(méi)有索引,導(dǎo)致了大量的全表掃描,累積了大量的會(huì)話(huà)數(shù),造成數(shù)據(jù)庫(kù)性能的下降,應(yīng)用與數(shù)據(jù)庫(kù)之間出現(xiàn)連接錯(cuò)誤。
案例三:
隱式轉(zhuǎn)換導(dǎo)致全表掃描
問(wèn)題描述:用戶(hù)網(wǎng)站打開(kāi)緩慢,質(zhì)疑RDS 性能不好。
可能原因:用戶(hù)的數(shù)據(jù)存放在RDS 中,網(wǎng)站訪問(wèn)數(shù)據(jù)庫(kù)的時(shí)間較長(zhǎng),大多web應(yīng)用程序設(shè)計(jì),SQL沒(méi)有優(yōu)化或索引建立的不好導(dǎo)致;
問(wèn)題排查:通過(guò)查看數(shù)據(jù)庫(kù)的慢日志,發(fā)現(xiàn)大量的慢sql,執(zhí)行時(shí)間超過(guò)了2S。
UPDATE USER SET xx=xx+N.N WHERE
account=130000870343 LIMIT 10
SELECT * FROM USER WHERE
account=13056870 LIMIT 10
懷疑在user 表上是否建立索引:
CREATE TABLE `user` (
`id` smallint(5) unsigned NOT NULL
AUTO_INCREMENT,
`account` char(11) NOT NULL COMMENT ‘???’,
…………………….
…………………….
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`account`),
…………………….
) ENGINE=InnoDB CHARSET=utf8 ;
查看執(zhí)行計(jì)劃,居然查詢(xún)使用了全表掃描:
db@3027 16:55:06>explain
select * from user where
account=13056870343;
+—-+————-+——–+——+—————+——+———+——+——+————-+
| id | select_type | table | type |
possible_keys | key | key_len | ref |
rows | Extra |
+—-+————-+——–+——+—————+——+———+——+——+————-+
| 1 | SIMPLE | t_user | ALL | username |
NULL | NULL | NULL | 799 |
Using where |
+—-+————-+——–+——+—————+——+———+——+——+————-+
1 row in set (0.00 sec)
為什么這里會(huì)是全表掃描?account 上不是已經(jīng)建立索引來(lái)嗎?仔細(xì)一看,account 定義為了字符串,而傳入的條件為數(shù)字,我們知道數(shù)字的精度是比字符串高的,所以這里做了隱士轉(zhuǎn)換:
to_number(account)=13056870343
(to_number 為將字符串轉(zhuǎn)換為數(shù)字),這樣即使account 上有索引,也沒(méi)法使用了,因此我們將傳入的數(shù)字改為字符串:
db@3027 16:55:13>EXPLAIN SELECT * FROM
USER WHERE
account='13056870343';
+----+-------------+--------+-------+---------------+----------+------
| id | select_type | TABLE | TYPE |
possible_keys | KEY |
key_len | REF | ROWS | Extra |
+----+-------------+--------+-------+---------------+----------+------
| 1 | SIMPLE | t_user | const | username |
username | 33
| const | 1 | |
+----+-------------+--------+-------+---------------+----------+------
1 ROW IN SET (0.00 sec)
可以看到數(shù)據(jù)已經(jīng)能夠索引到索引username 了。
總結(jié):由于用戶(hù)在設(shè)計(jì)表結(jié)構(gòu)的時(shí)候字段定義使用了字符串,而傳入的條件卻傳入了數(shù)字造成了隱士轉(zhuǎn)換,這是數(shù)據(jù)庫(kù)應(yīng)用中經(jīng)常出現(xiàn)的典型問(wèn)題; RDS足夠穩(wěn)定,但不論在怎么強(qiáng)的數(shù)據(jù)庫(kù),也經(jīng)不起劣質(zhì)SQL的挑戰(zhàn),優(yōu)化sql是長(zhǎng)期的一項(xiàng)優(yōu)化措施。
從上面的三個(gè)案例,我們可以總結(jié)一下,用戶(hù)在使用RDS
的時(shí)候,發(fā)現(xiàn)數(shù)據(jù)庫(kù)執(zhí)行sql 超時(shí),性能較差,連接超時(shí)等等這些問(wèn)題,大多數(shù)情況下,是由于應(yīng)用程序的設(shè)計(jì),sql 沒(méi)有優(yōu)化,或者索引建立的不好而導(dǎo)致;除非實(shí)例不可用(主機(jī)down 掉,實(shí)例服務(wù)停掉,實(shí)例由于空間太大而被鎖定)而導(dǎo)致用戶(hù)應(yīng)用不可用(實(shí)例的故障RDS 會(huì)有監(jiān)控報(bào)警)。
總結(jié)
以上是生活随笔為你收集整理的mysql迁移之后读取速度变慢_如何解决数据库迁移之后变慢的问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: c语言局部变量存在什么区_C语言程序设计
- 下一篇: 设置mysql整形_mysql 整型字