日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL的查询性能优化——《深究MySQL》

發布時間:2025/3/20 数据库 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL的查询性能优化——《深究MySQL》 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

更新中。。。。。。。

#寫在前面

mysql查詢緩慢的原因有哪些?
1.查詢語句是否請求了不必要的多余數據
2.
總結以上原因之后,優化數據庫性能,就需從以下幾個方面著手:
1.

說明:下面的知識為零散的記錄,后期需要整理

一、Mysql優化


1.優化insert和update

1.1 批量插入:將多條要插入的數據合并成一條

  • 合并后日志量(MySQL的binlog和innodb的事務讓日志)減少了,降低日志刷盤的數據量和頻率,從而提高效率;
  • 通過合并SQL語句,減少網絡傳輸的IO;
  • 通過合并SQL語句,減少SQL語句解析的次數;

注意事項:數據庫sql長度是有限制,sql長度過大會溢出報錯。可通過max_allowed_packet配置修改,默認是1M

1.2 事務插入:在開始插入前開啟事務,插入完的提交事務

  • 進行一個INSERT操作時,MySQL內部會建立一個事務,在事務內才進行真正插入處理操作。通過使用事務可以減少創建事務的消耗;

注意事項:事務日志大小也有限制,過大會刷磁盤,導致性能下降。可通過innodb_log_buffer_size配置修改

1.3 主鍵順序插入:前面插入數據和主鍵和后插入數據的主鍵是有序的

  • 如果有序,新插入的記錄直接定位在索引的最后面,索引的定位效率會很高,也且對索引調整也較小。

  • 如果無序,新插入的記錄可能要定位到索引中間,索引定位效率下降,而這時還需要B+tree進行分裂合并等處理,會消耗比較多計算資源,數據量較大時會有頻繁的磁盤操作。

參考:https://www.2cto.com/database/201707/654686.html

2. in 和 exsits的區別和效率

參考:https://www.cnblogs.com/emilyyoucan/p/7833769.html
總結如下:
select a.* from A a where exists(select 1 from B b where a.id=b.id)
exists()適合B表比A表數據大的情況

select * from A where id in(select id from B)
in()適合B表比A表數據小的情況

2.not in 和not exists

如果查詢語句使用了not in ,那么內外表都進行全表掃描,沒有用到索引;而not extsts 的子查詢依然能用到表上的索引。所以無論那個表大,用not exists都比not in要快。

3. 要建索引的MySQL字段盡量設置為NOT NULL

含有空值的列很難進行查詢優化,而且表索引是不會存儲NULL值的,所以如果索引的字段可以為NULL,索引的效率會下降很多。
因為它們使得索引、索引的統計信息以及比較運算更加復雜。
你應該用0、一個特殊的值或者一個空串代替空值。

4.負向查詢不能使用索引

反例:select name from user where id not in (1,3,5);
正例:select name from user where id in (2,4,6);

5. 前導模糊查詢不能使用索引

反例:select name from user where name like '%zhang ’
正例:select name from user where name like ‘zhang%’

6. 不對索引字段進行計算(不然索引會失效)

反例:select name from user where FROM_UNIXTIME(create_time) < CURDATE();
正例:select name from user where create_time < FROM_UNIXTIME(CURDATE());

7.保證參數的數據類型與庫一致(不然會作強制轉換)

庫里 phone字段為varchar
反例:select name from user where phone=18810503732;
正例:select name from user where telno=‘18810503732’

8. 避免復合索引失效

說明:user表的username 和phone 字段創建了復合索引,且username在前面。
能利用到索引的SQL:
select username from user where username=‘zhangsan’ and phone =‘18810503732’

select username from user where phone =‘18810503732’ and username=‘zhangsan’

select username from user where username=‘zhangsan’

不能利用到索引的SQL:

select username from user where phone =‘18810503732’

這個類似于電話本,你先以用戶名字作了目錄,再按電話號作的目錄。如果你先查電話的目錄的話,肯定是不行的。你只能先安用戶名字去搜索。

非同步方法會不會受同步方法的影響?

SQL語句中or的使用方法注意事項

二、優化特定類型的查詢


1. 優化count查詢

1.盡量使用count(*)。當然也可以嘗試索引覆蓋,此時最好是主鍵。

count(columnName) 雖然也可以求出行數,但是它有一個致命的問題,那就是不統計為NULL的列。所以如果用列名代替*求行數的方式可能會出現統計錯誤。

2.優化關聯查詢

1.確保在ON或USING的關聯順序中第二個表的關聯列有索引

例如,當A表和B表的關聯順序是A、B,即SQL語句為select * from A left join B on A.cid = B.cid 時,需要保證在B表的cid列表創建索引,而A表的cid列有無索引對性能沒有影響。

2. 盡量讓group by 和order by 的表達式中只涉及到一個表中的列

分組的字段在一個表,排序的字段又在另外一個表中,這樣就很難利用到索引。

3.優化子查詢

1. 盡量使用關聯查詢代替子查詢

子查詢會創建臨時表,而臨時表又沒有任何索引

2. 子查詢優化的基本思路,就是消除嵌套層次,把子查詢與父查詢放在同一個層次去執行。
實現步驟:

把子查詢的FROM子句中的表對象,與上層的父FROM子句中的表對象做JOIN

再把子查詢的WHERE子句中的條件表達式,與上層的父WHERE子句中的條件表達式用“AND”操作符連接

4.優化group by

1. 不關心順序時,盡量用order by NULL 避免group by的默認排序(從而避免了文件排序)

group by子句如果沒有指定排序列,則會自動根據分組列進行默認升序排序,從而導致了文件排序。

有個一般人不會用的方式,那就是直接在 group by 字段A 后面加上ASC或DESC關鍵字,使得分組結果按分組列(字段A)進行升序或降序排序。
2. group by要求返回的所有字段,要么出現在聚合函數(avg、sum、count、max、min等)中,要么出現Group By后面作為分組依據,不然高版本的mysql會報錯。這是因為分組后,沒有通過聚合函數聚合的多行數據不知道怎么存放在一行了,高版本時可通過配置文件設置忽略,從而只選擇一行來存。
3. 注意:group by是先排序再分組,且是分組后再聚合。

4.1優化group by with rollup

可通過explain查看執行計劃,決定是否加with rollup

with rollup表示需要做超級聚合,即可統計分組結果中每組數據分組前的某些值,如我們需要統計各部門員工工資的平均值
select depId, avg(money) from user group by depId with rollup;

需要注意的是,用了with rollup后不能再使用order by關鍵字,但可以直接在分組字段后加asc或desc

參考:https://blog.csdn.net/id19870510/article/details/6254358

5.優化limit

1.盡量利用索引覆蓋做“延遲關聯"(延遲關聯也可以優化關聯查詢的limit子句)

在做分頁查詢時,如果遇到像limit 2000,20這樣偏移量大的查詢時,mysql會實際查詢2020條數據,然后拋棄前面2000條數據,只返回最后20條。這樣做的代價非常高。

limit 2000,20 這樣的分而之所以會慢,是因為offset。offset會導致mysql掃描大量不需要的行然后拋棄掉。所以平時我們看到 limit 1 這種寫法是與offset無關的,也就是說這種寫法不會很慢。順便提一下,limit 2000,20 是等價于 limit 20 offset 2000的

6.優化union查詢

1.如果不需要對查詢結果去重的話,盡量使用union all 而不是union。

union后沒跟all 時,會自動給臨時表加上distinct做唯一性檢查,從而降低性能。

2.巧用 limit

(SELECT * from sys_user where id < 2000 order by office_id ) UNION (SELECT * from sys_user WHERE id >2000 order by office_id ) order by office_id desc limit 20;

兩個括號里的子查詢都會將各自的數據全部放在一個臨時表中,然后從臨時表中取出20條數據,這時可以將每個子查詢都用上limit 20

(SELECT * from sys_user where id < 2000 order by office_id limit 20) UNION (SELECT * from sys_user WHERE id >2000 order by office_id limit 20 ) order by office_id desc limit 20;

這樣一來,臨時表中就只有40條數據了。需要注意的是,從臨時表取數據的順序是不確定的,所以要想按自定義的順序取,必須在全局加上order by ,如上面SQL上的紅色字。

7.優化 in 子查詢

1.將in子查詢用innor join改寫成關聯查詢

IN的子查詢在實際執行的時候會被mysql自動改寫成較緩慢的查詢(mysql有時候也會自以為是的,哈哈),如下查詢

select * from film where film_id IN(select film_id from film_actor where actor_id = 1)

會被改成寫:

select * from film where film_id exists (select film_id from film_actor where actor_id = 1 and film_actor.film_id = film.film_id )

從改寫后的語句可以看到,子查詢里面涉及到外部表 film 的film_id字段了,所以mysql會先對外部表film進行全表掃描,通過explain執行計劃也可以看到。

優化后的寫法為:

select * from film inner join film_actor ON film.film_id = film_actor.film_id WHERE film_actor.actor_id = 1;

8.優化 MAX()、MIN()

1. 通過order by 和limit來優化

如下,我們需要獲取最大值和最小值(前提是id值有索引)

優化前:
最小值:select min(id) from actor;
最大值:select max(id) from actor;

優化后:
最小值:select id from actor order by id asc limit 1;
最大值:select id from actor order by id desc limit 1;

從explain可以看出,雖然優化前和優化后都用到了索引,但是min和max函數進行了大量的掃描,而優化后只掃描了一行。

9.優化OR查詢

用UNION替換OR (僅適用于索引列)

對索引列使用OR將造成全表掃描。注意,該規則只針對多個索引列有效. 如果有column沒有被索引, 查詢效率可能會因為你沒有選擇OR而降低。

在下面的例子中, LOC_ID 和REGION上都建有索引:
高效: select log_id , log_desc , region from log where log_id = 10 UNION
select log_id , log_desc , region from log where region= “update”

低效: select log_id , log_desc , region from log where log_id = 10 OR region = “update”

如果你堅持要用OR, 那就建議你將返回記錄最少的索引列寫在最前面。

總結

以上是生活随笔為你收集整理的MySQL的查询性能优化——《深究MySQL》的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。