mysql sql優化策略 MySql更新優化策略

2021-10-17 17:51:50 字數 3860 閱讀 7566

模擬場景一:

給資料庫中的一張表的結構調整,新增幾個字段,後面對之前的資料進行重新整理,重新整理的內容是對其中的乙個已有欄位url進行匹配,然後更新新加的字段type和typeid。

後來就寫了個shell指令碼來刷資料,結果執行shell指令碼後我就懵了,怎麼這麼慢~~~

情景再現

create table `****speed` (

`uin` bigint(20) unsigned not null default 0,

`id` int(11) unsigned not null default 0,

`url` varchar(255) not null default '',

`type` int(11) unsigned not null default 0,

`typeid` varchar(64) not null default '',

key `uin_id` (`uin`,`id`)

) engine=innodb default charset=utf8;

表結構大概是上面這樣的(省略了好多字段),表中只有乙個聯合索引uin_id,而我在更新的時候是下面的思路:

首先根據乙個id範圍獲取到一定數量的資料

select id,url from funkspeed where id>=101 and id<=200;

遍歷所有的資料,對每一條資料進行更新

#首先對資料進行處理,匹配獲取type和typeid

update ****speed set type=[type],typeid=[typeid] where id=[id]

按照上面的思路搞了之後,發現更新特別的慢,平均每秒鐘3~5個左右,我也是醉了,我看看要更新的資料,總共有32w+條,這樣更新下來大概需要24h+,也就是1天還要多,額~~哭了,想想肯定是**出問題了。

發現問題

首先我想到的是是不是因為只有乙個程序在更新,導致很慢,我啟動了5個程序,將id分段了,就像下面這樣

./update_url.sh 0 10000 &

./update_url.sh 10000 20001 &

./update_url.sh 20001 30001 &

./update_url.sh 30002 40002 &

./update_url.sh 40003 50003 &

執行之後發現還是那樣,速度沒有提公升多少,還是每秒鐘更新3~5個左右,想想也是啊,時間不可能花費在插入資料之前的那些步驟(匹配、組裝sql語句、。。。),應該是插入的時候有問題

再來看看我的sql語句

select id,url from funkspeed where id>=101 and id<=200;,

這裡,試著在命令列執行了下,結果如下

mysql> select id,url from funkspeed where id>=0 and id<=200;

empty set (0.18 sec)

竟然花了0.18秒,這個時候我猜恍然大悟,聯合索引我沒有使用到,聯合索引生效的條件是——必須要有左邊的字段,用explain驗證下,果然是這樣:

mysql> explain id,url from funkspeed where id>=0 and id<=200;

| table       | type | possible_keys | key  | key_len | ref  | rows   | extra       |

| funkspeed   | all  | null          | null | null    | null | 324746 | using where |

1 row in set (0.00 sec)

然後使用聯合索引:

mysql> select uin,id from funkspeed where uin=10023 and id=162;

| uin        |   id     |

| 10023      | 162      |

1 row in set (0.00 sec)

mysql> explain select uin,id from funkspeed where uin=10023 and id=162;

| table       | type | possible_keys | key      | key_len | ref         | rows | extra       |

| funkspeed   | ref  | uin_id        | uin_id   | 12      | const,const |    4 | using index |

1 row in set (0.00 sec)

可以看到幾乎是秒查,這個時候基本可以斷定問題是出現在索引這個地方了

我select的時候次數比較少,每兩個select之間id相差10000,所以這裡可以忽略掉,而且這裡沒辦法優化,除非在id上面新增索引。

問題發生在

update ****speed set type=[type],typeid=[typeid] where id=[id]

這裡在更新的時候也是會用到查詢的,我的mysql版本是5.5,不能explain update,不然肯定可以驗證我所說的,這裡要更新32w+條資料,每條資料都會去更新,每條資料0.2s左右,這太嚇人了~~

解決問題

問題找到了,解決起來就容易多了~~

select的時候加了乙個欄位uin,改為下面這樣

select uin,id,url from funkspeed where id>=101 and id<=200;

然後更新的時候使用

update ****speed set type=[type],typeid=[typeid] where uin=[uin] id=[id]

這樣一來索引就是用上了。

三下五除二改好了**,試著啟動了乙個程序,看看效果如何,果然,效果提公升的不是一點點,平均30+次/s,這樣大概3個小時左右就可以完成所有的更新了。

模擬場景二:需求6個表 pid欄位 寫到對應的brand_id欄位

問題sql背景:專案有6個表的要根據pid欄位要寫入對應的brand_id欄位。但是這個其中有兩個表是千萬級別的。我的worker執行之後,線上的mysql主從同步立刻延遲了!執行了乙個多小時之後,居然延遲到了40分鐘,而且只更新了十幾萬行資料。問題sql如下:

update $tablename$

set brand_id = #newbrandid#

where pid = #pid#

and brand_id = 0

專案組的mysql專家幫我分析了下,因為pid欄位沒有索引,mysql引擎要逐行掃瞄出與傳入的pid值相等的列,然後更新資料,也就是要掃瞄完1000w+行磁碟資料才能執行完這個sql。更嚴重的是,這個千萬級的表裡面有多少個不同的pid,我就要執行多少個這樣的sql。

同事給我的建議的根據id欄位進行sql**層次的縱向分表。每次更新1000行的資料,這樣mysql引擎就不用每次在掃全表了,資料庫壓力是之前的萬分之一。而且id作為主鍵,是有索引的有索引,有索引能大大優化查詢效能,優化後的sql如下:

update $tablename$

set brand_id = #newbrandid#

where pid = #pid#

and brand_id = 0

and id between #startnum# and #endnum#

僅僅用了id限區間的語句,將乙個千萬級的大表**層次上進行縱向切割。重新上線worker後,mysql主從沒有任何延遲!而且經過監視,短短10分鐘就更新了十幾萬資料,效率是之前的6倍!更重要的是資料庫負載均衡,應用健康執行。

以上通過兩個問題模擬場景再現分析mysql更新優化策略,希望對大家在資料庫方面有所幫助。

MYSQL SQL優化流程

常去想想以前的東西,懷舊不是用感傷的,是溫故知新,加油!1 盡量將複雜的sql拆成幾個簡單的查詢 2 盡量使用表連線,減少使用過 in not in 3 儘量減少子查詢的使用或者將其合併出來 4 盡量將 in not in exists not exists變為 join 語句,減少 合併子查詢 1...

MySQL SQL語句優化

檢視表定義 show create table users 檢視表的索引 show index from users 你要獲取第乙個表的所有資訊,你說全表掃瞄快呢還是索引掃瞄快呢?所以當你查詢庫 包括left join中的臨時庫 的所有資訊時,資料庫會選擇最優方法 全表掃瞄!s表dept id na...

Mysql sql查詢優化

1.單個條件未加索引 對應的執行計畫 從查詢計畫中可以看出該查詢全表掃瞄,掃瞄行數 9000多行 2.增加唯一索引之後查詢 查詢時間縮短,然後再看查詢計畫 查詢計畫中,掃瞄行數中只有一行。上面建立的索引是唯一索引,常規索引中查詢計畫的type一般為ref 索引列和非索引列一起查詢,索引仍然會有效 單...