PHP的SQL語句優化


(轉)僅供自己學習,特此轉發

普遍遇到的慢SQL有以下三種:

 1.未走索引
 2.where條件里包含子查詢,多表聯查
 3.查詢大量數據

解決

一.索引:SQL中的高速公路

但凡優化SQL,首先要看的就是這條查詢是否走了索引。走索引的查詢和沒走索引的差距可謂雲泥之別。

可以看下面這個例子:

在一張大約3W數據量的用戶表中,兩種查詢方式在速度上的差距:

不走索引:

select * from kw_user_copy where new_id=1 時間: 0.321 s

走主鍵索引:

select * from kw_user_copy where id=1 時間: 0.002 s

執行時間上有着數百倍的差距。

這種差距如果放在一些大的嵌套中,譬如循環查詢500次,將成為非常致命的問題,甚至可能讓程序執行超時。

PS. 很多查詢條件也會導致SQL放棄索引而執行全表遍歷,譬如:

select id from item where num is null

這些細節也要引起注意。

實際項目中的例子:

select id as user_id, name, nickname, photo, status, sdk_key, sdk_status from kw_user where name = 'wallkop' AND password = '44209a6a592dea91bcf7d4dd53e47a5a' 時間: 0.247 s

這是一條非常常見的用戶登錄查詢。

直觀看起來,這條SQL似乎寫的非常完善了,根據name和password去查詢相關用戶的信息,怎么看都沒有優化的余地了。

我們也知道:name和password作為兩個string字段,通常是不會建立索引的,也就是說,這是一條必然不走索引的查詢。

這種查詢就沒有優化余地了嗎?

非也。

下面就是一個簡單的優化:

select id from kw_user where name = 'wallkop' AND password = '44209a6a592dea91bcf7d4dd53e47a5a' 時間: 0.060 s   select id as user_id, name, nickname, photo, status, sdk_key, sdk_status from kw_user where id=37215 時間: 0.001 s   總耗時:0.061 s

將一條查詢語句拆成兩條,第一條不走索引的查詢,我們盡量去簡化它,只查一個id字段,你會驚奇的發現:速度居然提升了4倍。

而第二條查詢用戶詳細信息的SQL,我們走了主鍵索引,僅僅用了0.001s。

如此一來,兩條查詢加起來總耗時才0.061s,比之前快了4倍。

這就是索引的靈活運用之道。

二.子查詢(多表聯查)優化

子查詢速度慢的原因非常簡單:

主查詢遍歷多少條數據,就要執行多少遍子查詢。

簡單來說,一張只有50條數據的表,普通查詢和復雜子查詢是沒什么速度差異的,但當數據量級達到幾萬甚至幾十萬的時候,這個差距就會非常明顯。

分析一條SQL語句來說明:

select id from kw_question where game_id=2 AND status=2 AND id in (select question_id from kw_answer where question_id = kw_question.id AND answer like "%瑞文%"); 時間: 0.063 s

在這個語句中,where末端是一個非常坑爹的模糊文字子查詢

但乍一看這條SQL速度似乎也不算太慢,其原因就在於:game_id=2和status=2這兩個查詢條件大幅度縮小了需要查詢的數據集范圍。

這就給我們了一個優化思路:

如果我能在執行子查詢前,盡可能的縮減它的“數據范圍”,不就可以提高查詢效率了么?

分析一個實際項目里的案例,根據數據特點突破了SQL速度的極限:

select id as question_id, question, game_id, modify_time, has_attachment, status from kw_question a where game_id=2 AND status in (0,1,2) AND not exists( select id from kw_answer where question_id=a.id and status != -1) order by a.create_time desc limit 0,20 時間: 3.160 s

上述SQL是一個問題列表頁的查詢語句,業務要求是把符合where條件的零回答數據篩選出來。

其實對於這種查詢,最簡單高效的方式是在字段里加一個answer_num,手動記錄每個問題下的答案數量。

但是由於相關業務比較復雜,涉及審核、關閉、二次編輯等流程,最終項目組放棄了這個字段的使用。


所依在kw_question表缺乏相關answer_num字段的情況下,查詢一個“零回答”的問題,就得去查其相關聯的表:kw_answer。

這就由一個簡單的單表查詢變成了多表聯查,大幅度增加了時間性能損耗。


平心而論,單純從SQL的角度來講,這條SQL已經沒啥能優化的了,在無法使用answer_num這個字段的情況下,它已經寫的蠻不錯了。

然而3.16秒的速度真的讓人無法接受。

於是開始思考:

首先EXPLAIN分析,發現主查詢中rows多達157269條,難怪這么慢。

結合“零回答”這個特點仔細想了想,發現某個問題一旦有了至少一個答案,就徹底擺脫了0回答,通常來講這個過程是不可逆的。

這就導致了這15W次查詢中,大部分查詢是廢查詢,因為你知道那些數據根本不會變動,但SQL還是把它們全部遍歷了一次。

 

三.大量數據查詢優化

1、首先分析有沒有用到索引

2、


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM