MySQL數據庫優化技巧有很多,這裡摘抄了一些許多程序員常用的MySQL優化方法,供參考及備忘。
下面以SELECT語句為例,不過DELETE和UPDATE語句中的WHERE子句優化和這裡SELECT 語句的Mysql優化技巧一樣,下面只列出了一部分的MySQL 優化方法實例。
減少括號嵌套:
WHERE ((a AND b) AND c OR (((a AND b) AND (c AND d))))
優化-> WHERE (a AND b AND c) OR (a AND b AND c AND d)
常量重疊,去除不必要的常量:
(a<b AND b=c) AND a=5 AND (5=5)
優化-> b>5 AND b=c AND a=5
如果不使用GROUP BY或分組函數(COUNT()、MIN()……),HAVING與WHERE合 並。所有常數的表在查詢中比其它表先讀出。常數表為:1. 空表或只有1行的表; 2. 與在一個PRIMARY KEY或UNIQUE索引的WHERE子句一起使用的表,這裡所有的索引 部分使用常數表達式並且索引部分被定義為NOT NULL。
從表中讀取越多的數據,查詢會變得更慢。始終指定你需要的列,這是一個非常良好的習慣。
在大多數情況下,DISTINCT子句可以視為GROUP BY的特殊情況。例如,下面的兩個數據庫查詢是等效的:
SELECT DISTINCT c1, c2, c3 FROM t1 WHERE c1 > const;
SELECT c1, c2, c3 FROM t1 WHERE c1 > const GROUP BY c1, c2, c3;
由於這個等效性,適用於GROUP BY查詢的優化技巧和方法也適用於有DISTINCT子句的查詢。
MySQL查詢可以啟用高速查詢緩存。這是提高數據庫性能的有效MySQL優化方法之一。當同一個查詢被執行多次時,從緩存中提取數據和直接從數據庫中返回數據快很多,小小的MySQL優化技巧。
使用EXPLAIN關鍵字是另一個MySQL優化技巧,了解MySQL正在進行什麼樣的數據庫查詢操作。
實現一個SELECT查詢(最好是比較復雜的一個,帶joins方式的),在裡面添加上你的關鍵詞解釋,在這裡我們可以使用PHPMyAdmin, 他會告訴你表中的結果。舉例來說,假如當我在執行joins時,正忘記往一個數據庫索引中添加列,EXPLAIN能幫助我找到問題的所在。
MySQL可以使用一個索引來滿足ORDER BY子句,而不需要額外的排序。下面看看ORDER BY 優化技巧和方法。
即使ORDER BY不確切匹配索引,只要WHERE子句中的所有未使用的索引部分和所有額外的ORDER BY 列為常數,就可以使用索引。在某些情況下,MySQL不能使用索引來解決ORDER BY,盡管它仍然行使用索引來找到匹配WHERE子句。如:
對不同的關鍵字使用ORDER BY:SELECT * FROM t1 ORDER BY key1, key2;
對關鍵字的非連續元素使用ORDER BY:SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2;
混合ASC和DESC:SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
用於查詢行的關鍵字與ORDER BY中所使用的不相同:SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
聯接許多表,並且ORDER BY中的列並不是全部來自第1個 用於搜索行的非常量表。(這是EXPLAIN輸出中的沒有const聯 接類型的第1個表)。
有不同的ORDER BY和GROUP BY表達式。
使用的表索引的類型不能按順序保存行。例如,對於HEAP表的HASH索 引情況即如此。
通過EXPLAIN SELECT ...ORDER BY,可以檢查MySQL是否可以使用索引來解決查詢。
文件排序優化不僅用於記錄排序關鍵字和行的位置,並且還記錄數據庫查詢需要的列。這樣可以避免兩次讀取行。
有時,當你要查詢一張表是,你知道自己只需要看一行。你可能會去的一條十分獨特的記錄,或者只是剛好檢查了任何存在的記錄數,他們都滿足了你的 WHERE子句。增加一個LIMIT 1會令你的查詢更加有效,這個方法是MySQL優化很有效的一個技巧。這樣數據庫引擎發現只有1後將停止掃描,而不是去掃描整個表或索引。
使用LIMIT row_count而不使用HAVING時,MySQL將 以不同方式處理數據庫查詢。
如果你用LIMIT只選擇一些行,當MySQL選 擇做完整的表掃描時,它將在一些情況下使用索引,涉及到MySQL索引優化。
如果你使用LIMIT row_count與ORDER BY,MySQL一旦找到了排序結果的第一個row_count行, 將結束排序而不是排序整個表。如果使用索引,將很快。如果必須進行文件排序(filesort),必須選擇所有匹配查詢沒有LIMIT子 句的行,並且在確定已經找到第1個row_count行 前,必須對它們的大部分進行排序。在任何一種情況下,一旦找到了行,則不需要再排序結果的其它部分,並且MySQL不再進行排 序。
當結合LIMIT row_count和DISTINCT時,MySQL一旦找到row_count個 唯一的行,它將停止。
在一些情況下,GROUP BY能通過順序讀取鍵(或在鍵上做排序)來解決,然後計算摘要直到關鍵字的值 改變。在這種情況下,LIMIT row_count將不計算任何不必要的GROUP BY值。
只要MySQL已經發送了需要的行數到客戶,它將放棄查詢,除非你正使用SQL_CALC_FOUND_ROWS。
LIMIT 0將總是快速返回一個空集合。這對檢查數據庫查詢的有效性是有用的。當使用MySQL API時,它也可以用來得到結果列的列類型。(該mysql優化技巧在MySQL Monitor中不工作,只顯示Empty set;應使用SHOW COLUMNS或DESCRIBE)。
當服務器使用臨時表來進行查詢時,使用LIMIT row_count子句來計算需要多少空間。
如果應用程序中包含多個連接查詢,你需要確保你鏈接的列在兩邊的數據庫表上都被索引。這會影響MySQL如何優化內部聯接操作。此外,加入的列,必須是同一類型。例如,你加入一個DECIMAL列,而同時加入另一個表中的int列,MySQL將無法使用其中至少一個 指標。這種方法即使字符編碼必須同為字符串類型。
若需要隨機顯示結果,MySQL可能 會為表中每一個獨立的行執行數據庫BY RAND()命令(這會消耗處理器的處理能力,不利於MySQL數據庫優化),這種方法然後給你僅返回一行。
程序員經常在創建一個VARCHAR(15)時並沒有意識到他們可以將IP地址以整數形式來存儲,沒有考慮到MySQL優化的問題。當你有一個INT類型時,你只占用4個字 節的空間,這是一個固定大小的領域。確定所操作的數據庫列是一個UNSIGNED INT類型的,因為IP地址將使用32位unsigned integer。
在MySQL中,LEFT JOIN和STRAIGHT_JOIN強制的表讀順序可以幫助聯接數據庫MySQL優化器更快地工作,因為檢查的表交換更少。
SELECT * FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) WHERE b.key=d.key;MySQL可以進行下面方法的LEFT JOIN優化:如果對於產生的NULL行,WHERE條件總為假,LEFT JOIN變為普通聯接。
例如,在下面的查詢中如果t2.column1為NULL,WHERE 子句將為false:
SELECT * FROM t1 LEFT JOIN t2 ON (column1) WHERE t2.column2=5;因此,可以安全地將查詢轉換為普通聯接:
SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1;這樣可以更快,因為如果可以使查詢更佳,MySQL可以在表t1之前使用表t2。 為了強制使用數據庫表順序,使用STRAIGHT_JOIN。
在MySQL數據庫中,CROSS JOIN語法上等價於INNER JOIN (它們可以彼此代替。在標准SQL中,它們不等價。INNER JOIN結合ON子句使用;CROSS JOIN 用於其它地方。
總的來說,在只包含內部聯接操作的聯接表達式中可以忽略括號。刪除括號並將操作組合到左側後,聯接表達式:
t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b=t3.b OR t2.b IS NULL) ON t1.a=t2.a轉換為表達式:
(t1 LEFT JOIN t2 ON t1.a=t2.a) LEFT JOIN t3 ON t2.b=t3.b OR t2.b IS NULL但是這兩個表達式不等效。不能忽視左外聯接操作的右操作數和右聯接操作的左操作數中的括號。也就是不能忽視外聯接操作中的內表達式中的括號。可以忽視其它 操作數中的括號(外部表的操作數)。
對於任何表t1、t2、t3和 屬性t2.b和t3.b的任何條件P,下面的表達式:
(t1,t2) LEFT JOIN t3 ON P(t2.b,t3.b)等價於表達式
t1,t2 LEFT JOIN t3 ON P(t2.b,t3.b)MySQL數據庫對於只包含內聯接(而非外聯接)的聯接表達式,可以刪除括號。 你可以移除括號並從左到右評估(或實際上,你可以按任何順序評估表)。對外聯接卻不是這樣。去除括號可能會更改結果。對外聯接和內聯接的結合,也不是這樣。去除括號可能會更改結果。
滿足GROUP BY子句的最一般的方法是掃描整個表並創建一個新的臨時表,表中每個組的所有行應為連續的,然後使用該臨時表來找到組並應用累積函數(如 果有)。在某些情況中,MySQL能夠做得更好,通過索引訪問而不用創建臨時表。數據庫MySQL索引優化是數據庫優化技巧常用的重要方法。
為GROUP BY使用數據庫索引的最重要的前提條件是 所有GROUP BY列引用同一索引的屬性,並且索引按順序保存其關鍵字(例如,這是B-樹索 引,而不是HASH索引)。是否用索引訪問來代替臨時表的使用還取決於在查詢中使用了哪部分索引、 為該部分指定的條件,以及選擇的累積函數。有兩種方法通過索引訪問執行GROUP BY查詢,組合操作結合所有范圍判斷式使用(如果有)。第2個方法首先執行范圍掃描,然後組合結果元組。