每個后端都應該知道的八個提升 SQL 性能的 Tips
作為一名后端程序員,可以說天天都要跟數據庫打交道,不管使用的是 MySQL, Oracle 還是 SQL Server,毫無疑問都逃不開 SQL,所以日常工作中對于 SQL 的性能優化可謂說十分重要。今天阿粉就帶大家看一下,每個后端程序員都應該知道的十個提升查詢性能的技巧。
1.使用 Exists 代替子查詢
子查詢在日常的工作中不可避免一定會使用到,很多時候我們的用法都是這樣的:
SELECT Id, Name
FROM Employee
WHERE DeptId In (SELECT Id
FROM Department
WHERE Name like '%Management%');
相信大家平??隙ǘ际沁@樣來使用的,其實還有一種更好的方法,如下所示:
SELECT Id, Name
FROM Employee
WHERE DeptId Exist (SELECT Id
FROM Department
WHERE Name like '%Management%');
這里我們使用 exist 關鍵字而不是 In 關鍵字,當然如果在數據量不大的時候,兩種方式都可以,但是當數據量很大的時候,exist 的方式會比 in 的方式效率高很多。因為 Exist 函數根據查詢結果返回一個布爾值,速度會快很多。
2.適當的使用 JOIN 來代替子查詢
除了上面的exist 之外在有些場景我們可以使用 JOIN 來替換子查詢,畢竟子查詢的效果是很差的,如下所示:
SELECT Id, Name
FROM Employee
WHERE DeptId in (SELECT Id
FROM Department
WHERE Name like '%Management%');
使用 JOIN 的方式如下:
SELECT Emp.Id, Emp.Name,Dept.DeptName
FROM Employee Emp
RIGHT JOIN Department Dept on Emp.DeptId = Dept.Id WHERE Dept.DeptName like '%Management%';
3.使用 Where 替代不必要的Having
對于 where 的使用相信大家都很擅長,但是對于 Having 的使用可能平時用的不多,阿粉這里只能說:用得不多,挺好的!對于 Having 我們是能不用就不用不到萬不得已的時候不要用,說真的阿粉工作這么多年,真沒有使用 Having 的場景。我們先看下面的示例:
Having 的用法
SELECT Emp.Id, Emp.Name,Dept.DeptName,Emp.Salary
FROM Employee Emp
RIGHT JOIN Department Dept on Emp.DeptId = Dept.Id
GROUP BY dept.DeptName
HAVING Emp.Salary >= 20000;
Where 的用法
SELECT Emp.Id, Emp.Name,Dept.DeptName,Emp.Salary
FROM Employee Emp
RIGHT JOIN Department Dept on Emp.DeptId = Dept.Id
WHERE Emp.Salary >= 20000;
為什么說 Having 的性能沒有 Where 高呢?那是因為 Where 是一種精確的匹配,但是 Having 是需要配合 Group By 來配合使用,只要涉及到 Group By 自然就效率高不起來了。
4.使用精確的字段類型
有些小伙伴為了系統的可擴展性或者壓根就不知道該把數據庫字段的類型設置什么,所以就全部使用 char 或者 varchar,總覺得這樣更靈活,但是往往這個時候是對系統的最大隱患。
在使用時間類型的字段的時候,就需要設置成 DateTime,不能用 varchar;在使用標識是否刪除的時候就應該使用 tinyint,能用 varchar 的就不要用 char;對于大字段 text 需要獨立出來,這樣在查詢的時候就不會影響性能;對于能設置成唯一鍵的就需要設置成唯一鍵,因為你永遠無法避免程序會出現臟數據,要在數據層保證一致性。
5.使用批處理代替循環
在插入數據的時候的,我們可以使用 values 來批量進行插入,而不是通過循環來進行單條數據的查詢,如下所示:
//不可取
For(Int i = 0;i <= 5; i++)
{
INSER INTO Table1(Id,Value) Values( i , 'Value' + i );
}
//推薦
INSERT INTO Table1(Id, Value)
Values(1,Value1),(2,Value2),(2,Value3),(4,Value4),(5,Value5);
不過要注意 values 后面的數量也是有限制的,所以兩者可以結合使用,具體的可以根據表字段的多少來決定分多少批來執行。另外這里有一個注意的點,很多系統都會底層做操作日志,而且很多時候可能是 SQL 級別的,那這個時候就需要注意,記錄操作日志的表的字段是有長度限制的,這里整個 SQL 的長度是不能超過日志字段的長度的。
6.使用 UNION ALL 替代 UNION
在使用聯合查詢的時候,很多時候我們會使用到 UNION ALL 或者 UNION 來聯合多個表,進行匯總。那么 UNION ALL 和 UNION 的區別是什么呢?這兩個的區別是 UNION ALL 會返回聯合后的所有行記錄,而 UNION 是會進行去重后返回。
比如說我們有兩張表 teacher 和 student,里面的數據分別是下面:
這里這兩張表當中,存在相同的一條數據,就是(4, 馬六)這一條數據,我們可以看看使用 UNION ALL 和 UNION 的效果。
可以看到第二次的查詢結果中已經少了一行,說明我們上面說的 UNION 會去重的邏輯是存在的,而且去重是全字段都相同的時候才會被去重。
7.用精確的字段代替 *
另一個比較影響性能的點是使用 *,很多小伙伴為了省事,在編寫查詢語句的時候,會使用 * 來代替所有的字段,其實并不是說這種寫法有什么問題,只是這種寫法有點不可控,使用 * 表示要查詢所有字段,當我們的表是一個很簡單的表,而且里面的字段都是一些小字段的時候,使用 * 完全是可以的。
但是如果是對于一些大表特別是有 text 這種大字段的表,或者是一些敏感數據的表,我們還使用 * 號去查詢數據的話,就會有很大的問題了,一方面是有安全隱患,一方面還是增加磁盤,內存和網絡的傳輸,完全得不償失。
8.給必要的字段增加索引
索引作為數據庫里面一個很重要的內容,相比大家都不陌生,給必要的字段加上索引也是很有必要的,除了主鍵索引,我們還可以添加聚簇索引和唯一索引。
總結
后端程序員除了跟服務器打交道之外最多的就是跟數據庫打交道了,如何在數據庫層面提效也是一個長久的話題,這也是為什么數據庫能得到發展的原因,從關系型數據庫到 NoSQL 數據庫,從 MySQL 到 ClickHouse,數據庫行業也在長久的發展。