1. 程式人生 > >後端程式設計師必備:書寫高質量SQL的30條建議

後端程式設計師必備:書寫高質量SQL的30條建議

### 前言 本文將結合例項demo,闡述30條有關於優化SQL的建議,多數是實際開發中總結出來的,希望對大家有幫助。 ### 1、查詢SQL儘量不要使用select *,而是select具體欄位。 反例子: ``` select * from employee; ``` 正例子: ``` select id,name from employee; ``` 理由: - 只取需要的欄位,節省資源、減少網路開銷。 - select * 進行查詢時,很可能就不會使用到覆蓋索引了,就會造成回表查詢。 ### 2、如果知道查詢結果只有一條或者只要最大/最小一條記錄,建議用limit 1 假設現在有employee員工表,要找出一個名字叫jay的人. ``` CREATE TABLE `employee` ( `id` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, `date` datetime DEFAULT NULL, `sex` int(1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ``` 反例: ``` select id,name from employee where name='jay' ``` 正例 ``` select id,name from employee where name='jay' limit 1; ``` 理由: - 加上limit 1後,只要找到了對應的一條記錄,就不會繼續向下掃描了,效率將會大大提高。 - 當然,如果name是唯一索引的話,是不必要加上limit 1了,因為limit的存在主要就是為了防止全表掃描,從而提高效能,如果一個語句本身可以預知不用全表掃描,有沒有limit ,效能的差別並不大。 ### 3、應儘量避免在where子句中使用or來連線條件 新建一個user表,它有一個普通索引userId,表結構如下: ``` CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userId` int(11) NOT NULL, `age` int(11) NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`), KEY `idx_userId` (`userId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ``` 假設現在需要查詢userid為1或者年齡為18歲的使用者,很容易有以下sql 反例: ``` select * from user where userid=1 or age =18 ``` 正例: ``` //使用union all select * from user where userid=1 union all select * from user where age = 18 //或者分開兩條sql寫: select * from user where userid=1 select * from user where age = 18 ``` 理由: - 使用or可能會使索引失效,從而全表掃描。 >對於or+沒有索引的age這種情況,假設它走了userId的索引,但是走到age查詢條件時,它還得全表掃描,也就是需要三步過程: 全表掃描+索引掃描+合併 如果它一開始就走全表掃描,直接一遍掃描就完事。 mysql是有優化器的,處於效率與成本考慮,遇到or條件,索引可能失效,看起來也合情合理。 ### 4、優化limit分頁 我們日常做分頁需求時,一般會用 limit 實現,但是當偏移量特別大的時候,查詢效率就變得低下。 反例: ``` select id,name,age from employee limit 10000,10 ``` 正例: ``` //方案一 :返回上次查詢的最大記錄(偏移量) select id,name from employee where id>10000 limit 10. //方案二:order by + 索引 select id,name from employee order by id limit 10000,10 //方案三:在業務允許的情況下限制頁數: ``` 理由: - 當偏移量最大的時候,查詢效率就會越低,因為Mysql並非是跳過偏移量直接去取後面的資料,而是先把偏移量+要取的條數,然後再把前面偏移量這一段的資料拋棄掉再返回的。 - 如果使用優化方案一,返回上次最大查詢記錄(偏移量),這樣可以跳過偏移量,效率提升不少。 - 方案二使用order by+索引,也是可以提高查詢效率的。 - 方案三的話,建議跟業務討論,有沒有必要查這麼後的分頁啦。因為絕大多數使用者都不會往後翻太多頁。 ### 5、優化你的like語句 日常開發中,如果用到模糊關鍵字查詢,很容易想到like,但是like很可能讓你的索引失效。 反例: ``` select userId,name from user where userId like '%123'; ``` 正例: ``` select userId,name from user where userId like '123%'; ``` 理由: - 把%放前面,並不走索引,如下: ![](https://user-gold-cdn.xitu.io/2020/3/20/170f7f2739040e5b?w=1280&h=330&f=png&s=129628) - 把% 放關鍵字後面,還是會走索引的。如下: ![](https://user-gold-cdn.xitu.io/2020/3/20/170f7f224aa3dfed?w=1280&h=314&f=png&s=126373) ### 6、使用where條件限定要查詢的資料,避免返回多餘的行 假設業務場景是這樣:查詢某個使用者是否是會員。曾經看過老的實現程式碼是這樣。。。 反例: ``` List