Mysql_查詢優化_劉益長
一、 count優化
#建立表 CREATE TABLE IF NOT EXISTS cnt ( id INT, NAME VARCHAR(10), age INT, tel VARCHAR(10) ); #建立儲存過程 DELIMITER $ CREATE PROCEDURE cnt() BEGIN #定義一個循壞變數 DECLARE i INT DEFAULT 0; WHILE(i<1000) DO BEGIN SELECT i; SET i=i+1; INSERT INTO cnt(id,NAME)VALUES(i,"zhang"); END; END WHILE; END $ DELIMITER ; #呼叫儲存過程 CALL cnt(); #查詢語句a SELECT COUNT(*) FROM cnt WHERE id > 5; #查詢語句b SELECT (SELECT COUNT(*) FROM cnt) - COUNT(*) FROM cnt WHERE id <= 5;
語句當行數超過11行的時候需要掃描的行數比b語句要多, b語句掃描了6行,此種情況下,b語句比a語句更有效率。當沒有where語句的時候直接select count(*) from world.city這樣會更快,因為mysql總是知道表的行數。
二、 避免使用不相容的資料型別。
例如float和int、char和varchar、binary和varbinary是不相容的。資料型別的不相容可能使優化器無法執行一些本來可以進行的優化操作。在程式中,保證在實現功能的基礎上,儘量減少對資料庫的訪問次數;通過搜尋引數,儘量減少對錶的訪問行數,最小化結果集,從而減輕網路負擔;能夠分開的操作儘量分開處理,提高每次的響應速度;在資料視窗使用SQL時,儘量把使用的索引放在選擇的首列;演算法的結構儘量簡單;在查詢時,不要過多地使用萬用字元如 SELECT * FROM T1語句,要用到幾列就選擇幾列如:SELECT COL1,COL2 FROM T1;在可能的情況下儘量限制儘量結果集行數如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,因為某些情況下使用者是不需要那麼多的資料的。不要在應用中使用資料庫遊標,遊標是非常有用的工具,但比使用常規的、面向集的SQL語句需要更大的開銷;按照特定順序提取資料的查詢
#資料不相容會拉低效率 INSERT INTO cnt(id)VALUES(12.3);
三、索引欄位上進行運算會使索引失效
儘量避免在WHERE子句中對欄位進行函式或表示式操作,這將導致引擎放棄使用索引而進行全表掃描
#索引列進行運算會讓索引失效 CREATE INDEX index_age ON cnt(age); SELECT * FROM cnt WHERE age > 18; SELECT * FROM cnt WHERE age * 2 > 36; CREATE INDEX index_age ON cnt(id); SELECT * FROM cnt WHERE id > 10000; SELECT * FROM cnt WHERE id * 2 > 20000;
四、避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等這樣的操作符.
因為這會使系統無法使用索引,而只能直接搜尋表中的資料。例如: SELECT id FROM employee WHERE id != “B%”
優化器將無法通過索引來確定將要命中的行數,因此需要搜尋該表的所有行。在in語句中能用exists語句代替的就用exists.
#建立表 CREATE TABLE IF NOT EXISTS emp ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), age INT, tel VARCHAR(10) ); #建立儲存過程 DELIMITER $ CREATE PROCEDURE emp() BEGIN #定義一個循壞變數 DECLARE i INT DEFAULT 0; WHILE(i<1000) DO BEGIN SELECT i; SET i=i+1; INSERT INTO emp(NAME,age)VALUES("zhang",i); END; END WHILE; END $ DELIMITER ; # 呼叫儲存過程 CALL emp(); SELECT * FROM emp; # 避免的情況 !=, <>, is null, is not null, in, not in SELECT COUNT(*) FROM emp WHERE age IN (SELECT age FROM emp WHERE id > 100); SELECT COUNT(*) FROM emp WHERE EXISTS (SELECT age FROM emp WHERE id > 100);
五、儘量使用數字型欄位.
一部分開發人員和資料庫管理人員喜歡把包含數值資訊的欄位 設計為字元型,這會降低查詢和連線的效能,並會增加儲存開銷。
這是因為引擎在處理查詢和連接回逐個比較字串中每一個字元,而對於數字型而言只需要比較一次就夠了。
# 儘量使用數字型欄位 CREATE TABLE IF NOT EXISTS t1 (c1 INT,c2 INT); CREATE TABLE IF NOT EXISTS t2 (c1 INT,c2 INT);
六、合理使用EXISTS,NOT EXISTS子句。
# 使用where > 0; SELECT SUM(t1.c1) FROM t1 WHERE (SELECT COUNT(*) FROM t2 WHERE t2.c2=t1.c2 > 0); # 使用exists SELECT SUM(t1.c1) FROM t1 WHERE EXISTS (SELECT COUNT(*) FROM t2 WHERE t2.c2=t1.c2);
七、能夠用BETWEEN的就不要用IN ,能夠用DISTINCT的就不用GROUP BY
# between 是連續的範圍,使用索引 SELECT * FROM emp WHERE age BETWEEN 100 AND 200; # in不連續的範圍,不能使用索引 SELECT * FROM emp WHERE age IN (100,150,200); # distinct去重:重複的資料取一個 SELECT DISTINCT NAME FROM emp; # group by分組 SELECT NAME FROM emp GROUP BY NAME;