慷慨是不明智的,舉例varchar(5)和varchar(200)存儲‘Word’的空間是同樣的,那爲何又說慷慨是不明智的呢?實驗證實更長的列會消耗更多的內存,由於mysql一般會分配固定大小的內存塊來保存內部值。尤爲是使用內存臨時表進行排序或操做時會特別槽糕。因此最好的策略是隻分配真正須要的空間。因此什麼數據選擇怎樣的數據類型也是很重要的。對於錢,提一句,使用int或者bigint進行存儲就夠了。mysql
1.切分查詢sql
有時候對於一個大查詢咱們須要「分而治之」,將大查詢切分紅小查詢,每一個查詢功能徹底同樣,值完成一小部分,每次只返回一下部分結果。刪除舊的數據就是一個很好的列子。按期地清除大量數據時,若是用一個大的語句一次性完成的話,則可能須要一次鎖住不少數據,佔滿整個事務日誌,耗盡系統資源,阻塞不少小的但重要的查詢。將一個大的delete語句切分多個較小的查詢能夠儘量小地影響mysql性能,同時還能夠減小mysql複製的延遲。例如:咱們須要每月運行一次下面的查詢:服務器
delete from message where create < date_sub(NOW(),INTERVAL 3 MONTH)
那麼能夠用相似下面的方法來完成:併發
rows_affected = 0 do { rows_affected = do_query( "delete from message where create < date_sub(NOW(),INTERVAL 3 MONTH) LIMIT 100000") }while rows_affected >0
一次刪除一萬行數據來講是一個比較高效並且對服務器影響也最小的作法。同時,須要注意的是,若是是每次刪除操做數據後,都暫停一下子再作下一次刪除,這樣也是能夠的。函數
2.子查詢和關聯查詢高併發
關聯查詢:post
select distinct id from film inner join actor using(film_id)
子查詢:性能
select id from film where exists(select * from actor where film.id = actor.id);
進行性能對比發現:子查詢比關聯查詢要快些。測試
總結: 一是不須要聽取那些關於子查詢的「絕對真理」,二是應該用測試來驗證對子查詢的執行計劃和響應時間的假設。注意子查詢有個bug,下面的寫法會鎖住table2中的一條記錄:優化
select ... from table1 where col=(select ... from table2 where ...)
若是遇到該bug,子查詢在高併發狀況下的性能,就會和在單線程測試時的性能相差甚遠。
3.在同一個表上查詢和更新
mysql不容許對同一個表同時進行查詢和更新。
4.優化特定類型的查詢
4.1優化COUNT()查詢
count()是一個特殊的函數,有兩種很是不一樣的做用:它能夠統計某個列值的數量,也能夠統計行數。在統計列值時要求列值是非空的(不統計null)。若是在count()的括號中指定了列或者列的表達式,則統計的就是這個表達式有值的結果數。
count()的另外一個做用是統計結果集的行數,當mysql確認括號內的表達式不可能爲空時,實際上就是在統計行數。最簡單的就是當咱們使用count(*)的時候,這種狀況下通配符*並不會像咱們猜測的那樣擴展成全部的列,實際上它會忽略全部的列而直接統計全部的行數。
簡單的優化
咱們如何快速查找到全部ID大於5的城市:
select count(*) from city where id >5
經過結果能夠看到該查詢須要掃描4097行數據。若是將條件反轉一下,先查找ID小於等於5的城市數,而後用總城市數一減就能獲得一樣的結果,卻能夠將掃描的行數減小到5行之內。
select (select count(*) from city)-count(*) from city where id <=5
5.延遲關聯
延遲關聯能夠優化關聯查詢中的limit子句:
select id , name from film inner join(select id from film order by tilte limit 50,5) as lim using(id)
若是知道詳細的位置,可使用下面的:
select id ,name from film where position between 50 and 54 order by postion;
假設查詢返回的主鍵爲16049 到 16030 的記錄,那麼下一頁就能夠從16030這個點開始:
select * from renal where id < 16030 order by id desc limit 20