1. 程式人生 > 其它 >sql int轉換為varchar_常見SQL優化實踐

sql int轉換為varchar_常見SQL優化實踐

技術標籤:sql int轉換為varcharsql varchar轉int型別

(1)負向條件查詢不能使用索引select * from user where status!=0 ,not in/not exists都不是好習慣可以優化為in查詢:select * from user where status in(1,2)

資料準備:

CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `name` varchar(32) DEFAULT NULL, `age` int(11) DEFAULT NULL, `status` int(1) DEFAULT NULL, KEY `index_status` (`status`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;INSERT INTO `user` VALUES ('1', '張三', '12', '0');INSERT INTO `user` VALUES ('2', '李四', '23', '1');INSERT INTO `user` VALUES ('3', '王五', '34', '2');//在status欄位新增索引

測試結果:

e53e375dd7c6845fbe64fc3c9a881ac2.png

type連線型別為:all(全表掃描)

4bd499eb69250cb67d5a673f43f02671.png

type連線型別為:ref(非註解唯一索引掃描)

(2)前導模糊查詢不能使用索引select * from user where name like '%張三' 而非前導模糊查詢則可以:select * from user where name like '張三%'

資料準備:

CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `name` varchar(32) DEFAULT NULL, `age` int(11) DEFAULT NULL, `status` int(1) DEFAULT NULL, KEY `index_name` (`name`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;INSERT INTO `user` VALUES ('1', '張三', '12', '0');INSERT INTO `user` VALUES ('2', '李四', '23', '1');INSERT INTO `user` VALUES ('3', '王五', '34', '2');//在name欄位新增索引

測試結果:

178e142c5650128bea8505452200f9e2.png

type連線型別為:all(全表掃描)

231a4ae3fa915e040ad3158dc51a3e9a.png

type連線型別為:range(範圍掃描)

(3)資料區分度不大的欄位不宜使用索引select * from user where sex=1原因:性別只有男,女,每次過濾掉的資料很少,不宜使用索引。經驗上能過濾80%資料時可以使用索引

(4)在屬性上進行計算不能命中索引select * from user where YEAR(birth_date) < = '2017' 即使date上建立了索引,也會全表掃描,可優化為值計算:select * from user where birth_date< = '2000-01-01'

資料準備

CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `name` varchar(32) DEFAULT NULL, `sex` int(1) DEFAULT NULL, `birth_date` date DEFAULT NULL, KEY `index_birth_date` (`birth_date`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;INSERT INTO `user` VALUES ('1', '張三', '0', '2010-02-03');INSERT INTO `user` VALUES ('2', '李四', '1', '2000-02-02');INSERT INTO `user` VALUES ('3', '王五', '1', '1998-09-09');//在birth_date上新增索引

測試結果:

7aa9027ea9709a715ffbebe5f6ef0625.png

全表掃描,沒有列出可能應用的索引

2552d4ca93c1ef7b9c796e268d82d83c.png

全表掃描,顯示可能應用在這張表中的索引

(5)如果業務大部分是單條查詢,使用Hash索引效能更好,例如使用者表select * from user where id=1或select * from user where name='張三',原因:B-Tree索引的時間複雜度是O(log(n))Hash索引的時間複雜度是O(1)

(6)允許為null的列,查詢有潛在大坑,單列索引不存null值,複合索引不存全為null的值,如果列允許為null,可能會得到"不符合預期”結果,所以請使用not null約束以及預設值

(7)複合索引最左字首,並不是值SQL語句的where順序要和複合索引一致,使用者表建立了(login_name, passwd)的複合索引,select * from user where login_name=? and passwd=? ; select * from user where passwd=? and login_name=?; select * from user where login_name=? 都能命中索引,他們都滿足複合索引最左字首。 然而select * from user where passwd=?不能命中索引,不滿足複合索引最左字首

資料準備

CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `login_name` varchar(32) DEFAULT NULL, `password` varchar(32) DEFAULT NULL, KEY `index_loginname_password` (`login_name`,`password`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;//在login_name,password列建立複合索引,KEY `index_loginname_password` (`login_name`,`password`)

測試結果:

d3c551e0c4f93934f51a6f68a52f66d8.png

三條sql語句都能命中索引

47788594521f8bdaa6a9b1b2641ad2f6.png

不滿足複合索引最左原則,不能命中索引

(8)如果明確知道只有一條結果返回,limit 1能夠提高效率select * from user where login_name=? 可以優化為:select * from user where login_name=? limit 1原因:你知道只有一條結果,但資料庫並不知道,明確告訴它,讓它主動停止遊標移動

(9)強制型別轉換會全表掃描select * from user where phone_no=13800001234你以為會命中phone_no索引麼?那就錯了,因為phone_no是varchar(11) ,所以13800001234會強制轉換型別,如果phone_no為bigint(20),那麼phone_no=13800001234和phone_no='13800001234'都會走索引

資料準備

CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `phone_no` varchar(11) DEFAULT NULL, KEY `index_phone_no` (`phone_no`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;//在phone_no列加索引,KEY `index_phone_no` (`phone_no`)

測試結果:

be0a471388e99d4301cd79df729bb52a.png

發生型別轉換,沒有走索引