sql語句上的優化:
1.避免使用select*,寫出查詢需要的具體字段
2.對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引
下面有些情況將導致引擎放棄索引而進行全表掃描:
3.在where子句中對字段進行null值的判斷 select id from t where num is null 可以在num上設置默認值0,確保表中num列沒有null值,然后這樣查詢: select id from t where num=0
4.不要在where子句中使用!=或<>
5.不要在where子句中使用or來連接條件 select id from t where num=10 or num=20 可以這樣查詢: select id from t where num=10 union all select id from t where num=20
使用"union all"的性能比"union"更高一些。因為當SQL 語句需要UNION兩個查詢結果集合時,這兩個結果集合會以UNION-ALL的方式被合並,
然后在輸出最終結果前進行排序。 如果用UNION ALL替代UNION, 這樣排序就不是必要了,效率就會因此得到提高。
6.in 和 not in 也要慎用,否則會導致全表掃描,如: select id from t where num in(1,2,3) 對於連續的數值,能用 between 就不要用 in 了: select id from t where num between 1 and 3
補充:並不是說in就百分之百導致索引失效,當in()括號中的字段為一個時,仍然會使用索引,多個字段時索引會失效
為什么會失效:
原因:mysql查詢優化器認為全表掃描時如果速度大於使用索引,就會不用索引,你可以使用FORCE INDEX
強制mysql使用索引
7.下面的查詢也將導致全表掃描: select id from t where name like '%abc%',通配符不能放在首部,也就是不能%xxx
8.應盡量避免在 where 子句中對字段進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如: select id from t where num/2=100 應改為: select id from t where num=100*2
9.應盡量避免在where子句中對字段進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如: select id from t where substring(name,1,3)='abc'--name以abc開頭的id 應改為: select id from t where name like 'abc%'
10.若索引是復合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統使用該索引, 否則該索引將不會被使用,並且應盡可能的讓字段順序與索引順序相一致
11.很多時候用 exists 代替 in 是一個好的選擇: select num from a where num in(select num from b) 用下面的語句替換: select num from a where exists(select 1 from b where num=a.num)
12.索引不適合在大量重復數據的字段上建立,否則sql查詢可能不會去利用索引,例如: 一表中有字段sex,male、female幾乎各一半,那么即使在sex上建了索引也對查詢效率起不了作用
13.雖然索引有利於查詢,但卻不利於增刪數據,也就是說在頻繁修改的字段上盡量不要創建索引
14.可以使用varchar來替代char,因為varchar長度可變,最大為65535字節,除去起始位和結束位占去了3個字節外,所以其整體長度最大為65532個字節,而char(M)定義的列長度固定,M取值為0-255
15.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗
16.在新建臨時表時,如果一次性插入數據量很大,那么可以使用 select into 代替 create table,避免造成大量 log , 以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然后insert。
17.使用連接(JOIN)來代替子查詢(Sub-Queries) MySQL從4.1開始支持SQL的子查詢。這個技術可以使用SELECT語句來創建一個單列的查詢結果,然后把這個結果作為過濾條件用在另一個查詢中。
例如,我們要將客戶基本信息表中沒有任何訂單的客戶刪除掉,就可以利用子查詢先從銷售信息表中將所有發出訂單的客戶ID取出來,然后將結果傳遞給主查詢,如下所示: DELETE FROM customerinfo WHERE CustomerID NOT IN (SELECT CustomerID FROM salesinfo) 使用子查詢可以一次性的完成很多邏輯上需要多個步驟才能完成的SQL操作,同時也可以避免事務或者表鎖死,並且寫起來也很容易。
但是,有些情況下,子查詢可以被更有效率的連接(JOIN)..替代。例如,假設我們要將所有沒有訂單記錄的用戶取出來,可以用下面這個查詢完成: SELECT * FROM customerinfo WHERE CustomerID NOT IN (SELECTC ustomerID FROM salesinfo) 如果使用連接(JOIN)..來完成這個查詢工作,速度將會快很多。尤其是當salesinfo表中對CustomerID建有索引的話,性能將會更好,查詢如下: SELECT * FROM customerinfo LEFT JOIN salesinfo ON customerinfo.CustomerID=salesinfo.CustomerID WHERE salesinfo.CustomerID ISNULL 連接(JOIN)..之所以更有效率一些,是因為MySQL不需要在內存中創建臨時表來完成這個邏輯上的需要兩個步驟的查詢工作
sql語句以外的優化:
18.事務
盡管我們可以使用子查詢(Sub-Queries)、連接(JOIN)和聯合(UNION)來創建各種各樣的查詢,但不是所有的數據庫操作都可以只用一條或少數幾條SQL語句就可以完成的。
更多的時候是需要用到一系列的語句來完成某種工作。但是在這種情況下,當這個語句塊中的某一條語句運行出錯的時候,整個語句塊的操作就會變得不確定起來。
設想一下,要把某個數據同時插入兩個相關聯的表中,可能會出現這樣的情況:第一個表中成功更新后,數據庫突然出現意外狀況,造成第二個表中的操作沒有完成,
這樣,就會造成數據的不完整,甚至會破壞數據庫中的數據。要避免這種情況,就應該使用事務,它的作用是:要么語句塊中每條語句都操作成功,要么都失敗。
換句話說,就是可以保持數據庫中數據的一致性和完整性。事物以BEGIN關鍵字開始,COMMIT關鍵字結束。在這之間的一條SQL操作失敗,那么,ROLLBACK命令就可以把數據庫恢復到BEGIN開始之前的狀態。 BEGIN; INSERT INTO salesinfo SET CustomerID=14; UPDATE inventory SET Quantity=11 WHERE item='book'; COMMIT; 事務的另一個重要作用是當多個用戶同時使用相同的數據源時,它可以利用鎖定數據庫的方法來為用戶提供一種安全的訪問方式,這樣可以保證用戶的操作不被其它的用戶所干擾。 事務四個特性:原子性,一致性,隔離性,永久性
19.鎖定表
盡管事務是維護數據庫完整性的一個非常好的方法,但卻因為它的獨占性,有時會影響數據庫的性能,尤其是在很大的應用系統中。由於在事務執行的過程中,數據庫將會被鎖定,
因此其它的用戶請求只能暫時等待直到該事務結束。如果一個數據庫系統只有少數幾個用戶來使用,事務造成的影響不會成為一個太大的問題;但假設有成千上萬的用戶同時訪問一個數據庫系統,
例如訪問一個電子商務網站,就會產生比較嚴重的響應延遲。
其實,有些情況下我們可以通過鎖定表的方法來獲得更好的性能。下面的例子就用鎖定表的方法來完成前面一個例子中事務的功能。
LOCK TABLE inventory WRITE SELECT Quantity FROM inventory WHERE Item='book'; ... UPDATE inventory SET Quantity=11 WHERE Item='book'; UNLOCKTABLES 這里,我們用一個select語句取出初始數據,通過一些計算,用update語句將新值更新到表中。包含有WRITE關鍵字的LOCKTABLE語句可以保證在UNLOCKTABLES命令被執行之前,
不會有其它的訪問來對inventory進行插入、更新或者刪除的操作。
20.使用外鍵
鎖定表的方法可以維護數據的完整性,但是它卻不能保證數據的關聯性。這個時候我們就可以使用外鍵。
例如,外鍵可以保證每一條銷售記錄都指向某一個存在的客戶。在這里,外鍵可以把customerinfo表中的CustomerID映射到salesinfo表中CustomerID,
任何一條沒有合法CustomerID的記錄都不會被更新或插入到salesinfo中。
CREATE TABLE customerinfo( CustomerIDINT NOT NULL,PRIMARYKEY(CustomerID))TYPE=INNODB; CREATE TABLE salesinfo( SalesIDNT NOT NULL,CustomerIDINT NOT NULL, PRIMARYKEY(CustomerID,SalesID), FOREIGNKEY(CustomerID) REFERENCES customerinfo(CustomerID) ON DELETE CASCADE)TYPE=INNODB; 注意例子中的參數“ON DELETE CASCADE”。該參數保證當customerinfo表中的一條客戶記錄被刪除的時候,salesinfo表中所有與該客戶相關的記錄也會被自動刪除。
如果要在MySQL中使用外鍵,一定要記住在創建表的時候將表的類型定義為事務安全表InnoDB類型。該類型不是MySQL表的默認類型。定義的方法是在CREATETABLE語句中加上TYPE=INNODB。如例中所示。
部分參考:
https://blog.csdn.net/weixin_42047611/article/details/81772149