mysql單表資料操作優化(一)
系統環境
window7+8g記憶體+250g硬碟+i5處理器+5000轉
1.建立表結構
CREATE TABLE `test` (
`uid` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
`zid` char(32) DEFAULT '' COMMENT '32位隨機主鍵',
`name` varchar(50) DEFAULT '' COMMENT '名稱',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=8000001 DEFAULT CHARSET=utf8 COMMENT='測試表';
2.用儲存過程+事務插入800萬條資料
DELIMITER $$
USE `test`$$
DROP PROCEDURE IF EXISTS `proc_insert`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_insert`()
BEGIN
DECLARE i INT;
SET i = 0;
START TRANSACTION;
WHILE(i<8000000) DO
INSERT INTO test(`zid`,`name`) VALUES(REPLACE (UUID(), '-', ''), CONCAT('abc',i));
SET i=i+1;
END WHILE;
COMMIT;
END$$
DELIMITER ;
3.呼叫儲存過程
call proc_insert();
測試過程如下:
1.插入800萬資料消耗時間30分鐘;
2.select count(*) from test;平均消耗時間13s;
使用explain進行解釋如下圖:
type = index 跟all相同都是全表掃描,不同是index比all快,因為all從硬碟讀取,index從索引讀取,索引檔案要比資料檔案小;
possible_key = null 沒有使用索引
key = primary 主鍵索引
key_len = 4 索引長度
ref = null 沒有列參與索引
rows = 7632456 查詢的行數,數字越大說明查詢的時間越長
extra 包含mysql查詢的詳細資訊
3.select * from test where name = 'abc0';平均消耗時間22s;
使用explain進行解釋如下圖:
type = all 全表掃描
key = null 沒有索引
rows = 7632456 查詢的行數,數字越大說明查詢的時間越長
4.select * from test where name = 'abc7999999';平均消耗時間22s;
使用explain進行解釋如下圖:
type = all 全表掃描
key =null 沒有索引
rows = 7632456 查詢的行數,數字越大說明查詢的時間越長
使 name = ’abc0‘ 是查詢第一條資料,name='abc7999999'查詢最後一條,查詢的效率是一樣的,都是全表掃描;我們可以為這兩條sql語句加上limit限制,只查一條:
select * from test where name = 'abc0' limit 1;
select * from test where name = 'abc7999999' limit 1;
使用explain進行解釋如下:
type = all 全表掃描
key =null 沒有索引
rows = 7632456 查詢的行數,數字越大說明查詢的時間越長
extra = Using where 表示我們使用了條件查詢即 limit 1;
通過以上查詢可以看出即使我們加了限制,無論是查第一條還是最後一條,查詢的效率還是一樣;查詢非常慢;
單表優化解決方案: 新增索引
create index test_name_index on test(`name`);
測試過程如下:
SELECT * FROM test WHERE `name` = 'abc0'; 查詢第一條
SELECT * FROM test WHERE `name` = 'abc7999999'; 查詢最後一條
新增索引之後,查詢時間平均為0.001s 查詢速度巨大的提升,驚訝;
我們在看看用explain解釋的情況:
type = ref 對於每個來自於前面的表的行組合,所有有匹配索引值的行將從這張表中讀取,不知道什麼意思
possible_keys = test_name_index 使用了索引,名稱為test_name_index
key = test_name_index 顯示MySQL實際決定使用的鍵(索引)
key_len = 153 索引的長度153
rows = 1 這是重點,使用索引之後只查詢一行,沒有進行全表掃描
extra: Using index condition 使用索引樹中的資訊而不需要進一步搜尋讀取實際的行來檢索表中的列資訊
接下來我們查詢count數量
select count(*) from test; 該查詢沒有條件,我們是用explain解釋如下:
type = index
key = test_name_index
key_len = 153
rows = 7632456
extra = Using index
說明即使使用了索引,在沒有條件的情況下查詢count的效率依然不好,查詢時間依然很慢;
現在我們在查詢count的基礎上新增條件
SELECT COUNT(*) FROM test WHERE `name` LIKE '%abc79999%';
SELECT COUNT(*) FROM test WHERE `name` LIKE 'abc79999%';
使用like進行模糊匹配的時候,'%%'全模糊查詢在索引上不起作用(如第一條sql);使用右模糊查詢才起作用(如第二條sql);
type = range 只檢索給定範圍的行,使用一個索引來選擇行。
rows = 110 這是重點,只查詢110行
extra: Using where;Using index; where子句用於限制哪一個行匹配下一個表或傳送到客戶
結論說明
1.單表中有大資料的時候,無論查詢第一條還是最後一條,無論加limit 1限制還是不加這個限制,沒有使用索引的情況下都是進行的全表掃描,並且效率特別低;
2.加入索引之後,查詢效率有飛躍般的提升,查詢不再進行全表掃描,而是從索引中直接查詢;
3.索引必須在where條件下才起作用;
4.索引在 like 查詢的時候,全模糊匹配所以不起作用,右模糊才起作用;
5.無論加不加索引,在沒有where條件的select count(*) 查詢中,查詢也是全表掃描,查詢效率非常低;
6.加入索引之後,只有加入where條件select count(*) 才能真正使索引起作用;