<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
資料庫調優的大致方向:
sql查詢優化技術有很多,大體分為物理查詢優化和邏輯查詢優化:
資料準備:
CREATE DATABASE atguigudb2; USE atguigudb2; ############# class 表 ################# CREATE TABLE `class` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `className` VARCHAR(30) DEFAULT NULL, `address` VARCHAR(40) DEFAULT NULL, `monitor` INT NULL , PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; ############# student 表 ################# CREATE TABLE `student` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `stuno` INT NOT NULL , `name` VARCHAR(20) DEFAULT NULL, `age` INT(3) DEFAULT NULL, `classId` INT(11) DEFAULT NULL, PRIMARY KEY (`id`) #CONSTRAINT `fk_class_id` FOREIGN KEY (`classId`) REFERENCES `t_class` (`id`) ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; ################################# SET GLOBAL log_bin_trust_function_creators=1; # 不加global只是當前視窗有效。 #隨機產生字串 DELIMITER // CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255) BEGIN DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ'; DECLARE return_str VARCHAR(255) DEFAULT ''; DECLARE i INT DEFAULT 0; WHILE i < n DO SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1)); SET i = i + 1; END WHILE; RETURN return_str; END // DELIMITER ; #假如要刪除 #drop function rand_string; #用於隨機產生多少到多少的編號 DELIMITER // CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11) BEGIN DECLARE i INT DEFAULT 0; SET i = FLOOR(from_num +RAND()*(to_num - from_num+1)) ; RETURN i; END // DELIMITER ; #假如要刪除 #drop function rand_num; #建立往stu表中插入資料的儲存過程 DELIMITER // CREATE PROCEDURE insert_stu( START INT , max_num INT ) BEGIN DECLARE i INT DEFAULT 0; SET autocommit = 0; #設定手動提交事務 REPEAT #迴圈 SET i = i + 1; #賦值 INSERT INTO student (stuno, NAME ,age ,classId ) VALUES ((START+i),rand_string(6),rand_num(1,50),rand_num(1,1000)); UNTIL i = max_num END REPEAT; COMMIT; #提交事務 END // DELIMITER ; #執行儲存過程,往class表新增亂資料 DELIMITER // CREATE PROCEDURE `insert_class`( max_num INT ) BEGIN DECLARE i INT DEFAULT 0; SET autocommit = 0; REPEAT SET i = i + 1; INSERT INTO class ( classname,address,monitor ) VALUES (rand_string(8),rand_string(10),rand_num(1,100000)); UNTIL i = max_num END REPEAT; COMMIT; END // DELIMITER ; #執行儲存過程,往class表新增1萬條資料 CALL insert_class(10000); #執行儲存過程,往stu表新增50萬條資料 CALL insert_stu(100000,500000); SELECT COUNT(*) FROM class; SELECT COUNT(*) FROM student; ############################### 刪除索引的儲存過程 ######################## DELIMITER // CREATE PROCEDURE `proc_drop_index`(dbname VARCHAR(200),tablename VARCHAR(200)) BEGIN DECLARE done INT DEFAULT 0; DECLARE ct INT DEFAULT 0; DECLARE _index VARCHAR(200) DEFAULT ''; DECLARE _cur CURSOR FOR SELECT index_name FROM information_schema.STATISTICS WHERE table_schema=dbname AND table_name=tablename AND seq_in_index=1 AND index_name <>'PRIMARY' ; #每個遊標必須使用不同的declare continue handler for not found set done=1來控制遊標的結束 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=2 ; #若沒有資料返回,程式繼續,並將變數done設為2 OPEN _cur; FETCH _cur INTO _index; WHILE _index<>'' DO SET @str = CONCAT("drop index " , _index , " on " , tablename ); PREPARE sql_str FROM @str ; EXECUTE sql_str; DEALLOCATE PREPARE sql_str; SET _index=''; FETCH _cur INTO _index; END WHILE; CLOSE _cur; END // DELIMITER ; # 執行儲存過程 CALL proc_drop_index("dbname","tablename");
# 【1】. 全值匹配 # student表,主鍵id,此時無索引,耗時大 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age = 30; EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age = 30 AND classId = 4; EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age = 30 AND classId = 4 AND NAME = 'abcd'; # 注:SQL_NO_CACHE 不使用查詢快取 # 建立索引 CREATE INDEX idx_age ON student(age); CREATE INDEX idx_age_classid ON student(age,classId); CREATE INDEX idx_age_classid_name ON student(age,classId,NAME); # 此時第三條查詢語句預設使用最後一條索引,而不是前兩個
# 【2】. 最佳左字首法則 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.age = 30 AND student.name = 'abcd'; # 查age&name,用age的索引 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.classid = 1 AND student.name = 'abcd'; # 查classid&name,classid在前,有索引的話先找classid相同的,再找name, #但現在沒有這樣的索引,idx_age_classid_name的欄位順序是先找age,所以不符合,所以此時不能用索引 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE classid = 4 AND student.age = 30 AND student.name = 'abcd'; #idx_age_classid_name 聯合索引中所有欄位均出現,可以使用該索引 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.age = 30 AND student.name = 'abcd'; # 現在,刪除idx_age和idx_age_classid,發現用到idx_age_classid_name,而key_len=5,即只用到age欄位,int(4)+null(1) #因為索引完age後沒有classid了,不能再查詢到name
在定義表時,讓主鍵auto_increment,否則,插入一條資料時可能會移動大量資料。
如,往 1 5 8 10 15 … 100 中插9,會放在8 10 中間,因為索引預設升序排列。那麼10往後的資料都要挪動,頁不夠時又要放到下一頁,每插一條資料都這樣挪一次,開銷很大
我們自定義的主鍵列id 擁有AUTO_INCREMENT 屬性,在插入記錄時儲存引擎會自動為我們填入自增的主鍵值。這樣的主鍵佔用空間小,順序寫入,減少頁分裂。
# 【4】. 計算、函數、型別轉換(自動或手動)導致索引失效 ##### 例1: EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name LIKE 'abc%'; #更好,能夠使用上索引 # type=range 使用了索引中的排序 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE LEFT(student.name,3) = 'abc'; # left(text,num_chars):擷取左側n個字元 # type = all 全表的存取 # 該語句的執行過程:針對每一條資料,一個一個取出,先作用一遍函數,再拿函數結果與abc對比,用不上b+樹 CREATE INDEX idx_name ON student(NAME); ##### 例2: CREATE INDEX idx_sno ON student(stuno); EXPLAIN SELECT SQL_NO_CACHE id,stuno,NAME FROM student WHERE stuno+1 = 900001; # type = all 需要做運算,無法直接用索引找值 EXPLAIN SELECT SQL_NO_CACHE id,stuno,NAME FROM student WHERE stuno = 900000; # type = ref
# 【5】. 型別轉換導致索引失效 # 未使用到索引 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME=123; # 這裡使用了隱式轉換 # 使用到索引 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME='123'; # name本身就是字串型別
# 【6】. 範圍條件右邊的列索引失效 ( > < >= <= between 等) SHOW INDEX FROM student; CALL proc_drop_index('atguigudb2','student'); CREATE INDEX idx_age_classid_name ON student(age,classId,NAME); EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.age = 30 AND student.classId > 20 AND student.name = 'abc'; # 這三個and先寫誰無所謂,優化器會調優 # key_len = 10, age=5,classId=5,name用不上。classId 是範圍,索引右側的name用不上 # 改寫索引: CREATE INDEX idx_age_name_cid ON student(age,NAME,classId); #把需要排序的classid放到最後 # 此時在執行上面的語句,就使用了這個索引,key_len=73
建立的聯合索引中,必須把涉及到範圍的欄位寫在最後。
# 【7】. 不等於(!= 或者<>)索引失效 CREATE INDEX idx_name ON student(NAME); EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name <> 'abc'; # 索引失效 索引查的是等於
# 【8】. is null可以使用索引,is not null無法使用索引 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age IS NULL; # type=ref 相當於等於某個值 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age IS NOT NULL; # 索引失效 相當於不等於
# 【9】. like以萬用字元%開頭索引失效 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME LIKE 'ab%'; # 可用索引 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME LIKE '%ab'; # type = all 索引失效
頁面搜尋嚴禁左模糊或者全模糊,如果需要請走搜尋引擎來解決。
# 【10】. OR 前後存在非索引的列,索引失效 CALL proc_drop_index('atguigudb2','student'); SHOW INDEX FROM student; # 建立一個age的索引 CREATE INDEX idx_age ON student(age); EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age = 10 OR classid = 100; # 未使用索引,索引+全表掃描->全表掃描 # 再加一個欄位的單獨索引 CREATE INDEX idx_cid ON student(classid); # 再執行上條語句,此時 type = index_merge ,key = idx_age,idx_cid。
統一使用utf8mb4( 5.5.3版本以上支援)相容性更好,統一字元集可以避免由於字元集轉換產生的亂碼。不同的字元集進行比較前需要進行轉換會造成索引失效。
到此這篇關於SQL索引失效的11種情況詳析的文章就介紹到這了,更多相關SQL索引失效內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45