在優化有問題的查詢時,目標應該是找到乙個更優的方法獲得實際需要的結果--而不一定總要從mysql獲取一模一樣的結果集。有時候可以查詢轉換一種寫法讓其返回一樣的結果,但是效能更好。但也可以通過修改應用**,用另一種方式完成查詢,最終達到一樣的目的。這裡我們將介紹如何通過這種方式來重構查詢,並展示合適需要使用這樣的技巧。
1 用乙個複雜的查詢還是多個簡單的查詢。
設計查詢的時候乙個需要考慮的重要問題是:是否需要將乙個複雜的查詢分成多個簡單的查詢。在傳統實現中,總是強調需要資料庫層完成盡可能多的工作,這樣做的邏輯在於以前我那個是認為網路通訊,查詢解析和優化是一件代價很高的事情。
但是這樣的想法對於mysql並不適用,mysql從設計上連線和斷開連線都是很輕量級的,在返回乙個小的查詢結果方面效率很高效。現代的網路速度比之前的要快很多,無論是頻寬還是延遲。在某些版本的mysql上,即使在乙個彤彤伺服器上,也能夠執行每秒超過10w的查詢,即使是乙個千兆網絡卡也能輕鬆滿足每秒超過2000次的查詢。索引執行多個小查詢限制已經不是很大的問題了。
mysql內部每秒能夠掃瞄記憶體中百萬行的資料,相比之下,mysql響應資料給客戶端就要慢得多了。在其他條件都相同的時候,使用盡肯能少的查詢當然是最好的。但是有時候,將乙個大查詢分解為多個小查詢是很有必要的。別害怕這樣做,好哈的衡量一下只有這是不是會減少工作量。稍微我們將通過本章的乙個例項來展示這個技巧的優勢。
2切分查詢
有時候對於乙個大查詢我們需要分而治之,將大查詢切分成小查詢,每個查詢功能完全一樣,值完成一小部分,每次只返回以小部分結果。
刪除舊的資料就是乙個很好的例子。定期的清理大量資料時,如果用乙個大的語句一次性完成的話,則可能要一次鎖住很多的資料,佔滿整個事務日誌,好近系統資源,阻塞很多小的但終於的查詢。將乙個大的delete語句切分成多個較小的查詢可以盡可能小的影響mysql的效能,同時還可以減少mysql複製的延遲。例如我們需要每個月執行一次下面的查詢:
delete from message where created < date_sub(now(),interval 3 month);
那麼可以用類似下面的辦法來完成同樣的工作:
rows_affected = 0
do}while rows_affected > 0
一次刪除1w行資料一般來說是乙個比較高效而且對伺服器影響也最小的做法(如果是事務型引擎,很多時候笑屎我能夠更高效)。同時需要注意的是,如果每次刪除資料後,都暫停一會再做下一次刪除,這樣也可以將伺服器上原本一次性的壓力分散到乙個很長的時間段中,就可以大大降低對伺服器的影響,還可以大大減少刪除時的鎖的持有時間。
3 分解關聯查詢
很多高新能的應用都會對關聯查詢進行分解。簡單的說,可以對每乙個表進行一次單錶查詢,然後將結果在應用程式中進行關聯,例如,下面的查詢:
select * from tag join tag_post on tag_post.tag_id = tag.tag_id join post on tag_post.post_id = post.id where tag.tag = 『mysql『
可以分解成下面的這些查詢來代替:
select * from tag where tag = 『mysql『;
select * from tag_post where tagid=1234;
select * from post where post_id in (123,234,435,342);
到底為什麼要這麼做?乍一看,這樣走並沒有什麼好處,原本一條查詢,這裡卻變成多條查詢,返回的結果又是一模一樣的的。事實上,用分解關聯查詢的方式重構查詢,有如下的優勢:
1讓快取的效率更高。許多應用程式可以方便的緩衝單錶查詢對應的結果物件。例如:啥忙查詢的tag已經被快取了,那麼應用就已經跳過第乙個查詢。再例如,應用中已經快取了id為123,234,345的內容,那麼第三個查詢的in()中就可以少了幾個id,另外對應mysql的查詢快取來說,如果關聯中的某個表發生了變化,那麼久無法使用查詢快取了,而拆分後,如果某個表很少改變,那麼基於該錶的查詢就可以重複利用查詢快取結果了。
2 將查詢拆分後,執行黨查詢可以減少鎖的競爭。
3 在應用層做關聯,可以更容易對資料庫進行拆分,更容易做到高新能和可擴充套件。
4 查詢本身下來也可能會有所提公升。這個例子中使用in()代替關聯查詢,可以讓mysql按照id順序進行查詢,這可比隨機的關聯要更高效。我們後續會詳細介紹這一點。
5 可以減少冗餘記錄的查詢。在應用層做關聯,意味著對於某條記錄應用只需要查詢一次,而在資料庫中做關聯查詢,則可能重複的訪問同一部分資料。從這點看,這樣的重構可能會減少網路和記憶體的消耗。
6更進一步,這樣做相當於在應用中實現了hash關聯,而不是使用mysql的巢狀迴圈關聯。某些場景中hash的關聯效率要高很多。
在很多場景下,通過重構查詢將關聯查詢放到應用長袖中將會更加高效,這樣的場景有很多,比如:當應用能夠方便的緩衝單個查詢的結果的時候,可以將資料分布到不同的mysql伺服器上的時候,能夠使用in()的方式代替關聯查詢的時候,單反查詢中使用同乙個資料表的時候。
原文:
重構之維 關於重構及《重構》的隨想
重構之維 關於重構及 重構 的隨想 重構 究竟重構了什麼?不止一次地,我聽到我們這個行業裡的大師們對重構技術提出 至少是 置疑 那是我們過去十五年裡一直在做的事 我從 上世紀 70年代就已經開始這樣做了 unix上的黑客們一直都是這樣做的 這些說辭讓我很有興趣探其究竟。在這本 重構 裡,martin...
為什麼要進行重構? 《重構》節選
我不想把重構說成治百病的萬靈丹,它絕對不是所謂的 銀彈 不過它的確很有價值,雖不是一顆銀子彈,卻是一把 銀鉗子 可以幫助你始終良好地控制自己的 重構是個工具,它可以 並且應該 為了以下數個目的而被運用 重構改進軟體設計 如果沒有重構,程式的設計會逐漸腐敗變質。當人們只為短期目的,或是在完全理解整體設...
重構讀書筆記 重構列表 20041028
title 重構讀書筆記 重構列表 20041028 content refactorings 重構 列表 1.add parameter 新增引數 2.change bidirectional association to unidirectional 將雙向關聯改為單項 3.change ref...