mysql-索引的使用及sql的一些優化

MySQL優化

一,查看SQL的執行效率

MySQL 客戶端連接成功後,通過一下語句查看服務器相關狀態

show [session|global] status 命令可以提供服務器狀態信息
show status like 'Com_______';

在這裏插入圖片描述

show status like 'Innodb_rows_%';

在這裏插入圖片描述

參數 含義
Com_select 執行 select 操作的次數,一次查詢只累加 1。
Com_insert 執行 INSERT 操作的次數,對於批量插入的 INSERT 操作,只累加一次。
Com_update 執行 UPDATE 操作的次數。
Com_delete 執行 DELETE 操作的次數。
Innodb_rows_read select 查詢返回的行數。
Innodb_rows_inserted 執行 INSERT 操作插入的行數。
Innodb_rows_updated 執行 UPDATE 操作更新的行數。
Innodb_rows_deleted 執行 DELETE 操作刪除的行數。
Connections 試圖連接 MySQL 服務器的次數。
Uptime 服務器工作時間。
Slow_queries 慢查詢的次數。

二,如何定位執行效率低的SQL語句

  • show processlist:show processlist命令查看當前MySQL在進行的線程,包括線程的狀態、是否鎖表等,可以實時地查看 SQL 的執行情況,同時對一些鎖表操作進行優化。

在這裏插入圖片描述

含義
id 用戶登錄mysql時,系統分配的"connection_id",可以使用函數connection_id()查看
user 顯示當前用戶。如果不是root,這個命令就只顯示用戶權限範圍的sql語句
host 顯示這個語句是從哪個ip的哪個端口上發的,可以用來跟蹤出現問題語句的用戶
db 顯示這個進程目前連接的是哪個數據庫
command 顯示當前連接的執行的命令,一般取值爲休眠(sleep),查詢(query),連接(connect)等
time 顯示這個狀態持續的時間,單位是秒
state 顯示使用當前連接的sql語句的狀態
info 顯示sql語句
  • 慢查詢日誌
    慢查詢日誌記錄了所有執行時間超過參數long_query_time設置值並且掃描記錄數不小於 min_examined_row_limit 的所有的SQL語句的日誌

    慢日誌的設置

    # 該參數用來控制慢查詢日誌是否開啓, 可取值: 1 和 0 , 1 代表開啓, 0 代表關閉
    slow_query_log=1 
    
    # 該參數用來指定慢查詢日誌的文件名
    slow_query_log_file=slow_query.log
    
    # 該選項用來配置查詢的時間限制, 超過這個時間將認爲值慢查詢, 將需要進行日誌記錄, 默認10s
    long_query_time=10
    
    

三,explain分析執行計劃

通過以上步驟查詢到效率低的 SQL 語句後,可以通過 EXPLAIN或者 DESC命令獲取 MySQL如何執行 SELECT 語句的信息,包括在 SELECT 語句執行過程中表如何連接和連接的順序。

查詢SQL語句的執行計劃 :

在這裏插入圖片描述

字段 含義
id select查詢的序列號,是一組數字,表示的是查詢中執行select子句或者是操作表的順序。
select_type 表示 SELECT 的類型,常見的取值有 SIMPLE(簡單表,即不使用表連接或者子查詢)、PRIMARY(主查詢,即外層的查詢)、UNION(UNION 中的第二個或者後面的查詢語句)、SUBQUERY(子查詢中的第一個 SELECT)等
table 輸出結果集的表
type 表示表的連接類型,性能由好到差的連接類型爲( system —> const -----> eq_ref ------> ref -------> ref_or_null----> index_merge —> index_subquery -----> range -----> index ------> all )
possible_keys 表示查詢時,可能使用的索引
key 表示實際使用的索引
key_len 索引字段的長度
rows 掃描行的數量
filtered 實際顯示行數佔掃描rows的比例
extra 執行情況的說明和描述
  • id

    id 字段是 select查詢的序列號,是一組數字,表示的是查詢中執行select子句或者是操作表的順序

    • id相同,表示加載表的順序是從上到下
    EXPLAIN select * from t_role r, t_user u, user_role ur where r.id = ur.role_id and u.id = ur.user_id ;
    

在這裏插入圖片描述

  • id不同,id的值越大,優先級越高,越先被執行
  EXPLAIN SELECT * FROM t_role WHERE id = (SELECT role_id FROM user_role WHERE user_id = (SELECT id FROM t_user WHERE username = 'stu1'))

在這裏插入圖片描述

  • id有相同,有不同,同時存在的時候,id相同的認爲是一組,從上到下順序執行,在所有的組中,id值越大優先級越高越先執行
 EXPLAIN SELECT * FROM t_role r , (SELECT * FROM user_role ur WHERE ur.`user_id` = '2') a WHERE r.id = a.role_id ; 

在這裏插入圖片描述

  • select_type

    select_type表示select的類型

    select_type 含義
    SIMPLE 簡單的select查詢,查詢中不包含子查詢或者UNION
    PRIMARY 查詢中若包含任何複雜的子查詢,最外層查詢標記爲該標識
    SUBQUERY 在SELECT 或 WHERE 列表中包含了子查詢
    DERIVED 在FROM 列表中包含的子查詢,被標記爲 DERIVED(衍生) MYSQL會遞歸執行這些子查詢,把結果放在臨時表中
    UNION 若第二個SELECT出現在UNION之後,則標記爲UNION ; 若UNION包含在FROM子句的子查詢中,外層SELECT將被標記爲 : DERIVED
    UNION RESULT 從UNION表獲取結果的SELECT
  • table

    table表示展示的數據屬於哪個表

  • type
    type表示連接類型

    性能由好到差:
    NULL > system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
    

    常見的type如下:

    system > const > eq_ref > ref > range > index > ALL
    
    type 含義
    NULL MySQL不訪問任何表,索引,直接返回結果
    system 表只有一行記錄(等於系統表),這是const類型的特例,一般不會出現
    const 表示通過索引一次就找到了,const 用於比較primary key 或者 unique 索引。因爲只匹配一行數據,所以很快。如將主鍵置於where列表中,MySQL 就能將該查詢轉換爲一個常亮。const於將 “主鍵” 或 “唯一” 索引的所有部分與常量值進行比較
    eq_ref 類似ref,區別在於使用的是唯一索引,使用主鍵的關聯查詢,關聯查詢出的記錄只有一條。常見於主鍵或唯一索引掃描
    ref 非唯一性索引掃描,返回匹配某個單獨值的所有行。本質上也是一種索引訪問,返回所有匹配某個單獨值的所有行(多個)
    range 只檢索給定返回的行,使用一個索引來選擇行。 where 之後出現 between , < , > , in 等操作。
    index index 與 ALL的區別爲 index 類型只是遍歷了索引樹, 通常比ALL 快, ALL 是遍歷數據文件。
    all 將遍歷全表以找到匹配的行
  • possible_keys

    顯示可能應用在這張表的索引,一個或多個

  • key
    實際使用的索引, 如果爲NULL, 則沒有使用索引

  • key_len
    索引字段的長度

  • rows
    掃描行的數量

  • extra
    用於顯示MySQL在查詢過程中的一些詳細信息,MySQL查詢優化器執行查詢的過程中對查詢計劃的重要補充信息

內容 含義
Using filesort MySQL有兩種方式可以生成有序的結果,通過排序操作或者使用索引,當Extra中出現了Using filesort 說明MySQL使用了後者,但注意雖然叫filesort但並不是說明就是用了文件來進行排序,只要可能排序都是在內存裏完成的。大部分情況下利用索引排序更快,所以一般這時也要考慮優化查詢了。使用文件完成排序操作,這是可能是ordery by,group by語句的結果,這可能是一個CPU密集型的過程,可以通過選擇合適的索引來改進性能,用索引來爲查詢結果排序。
Using temporary 用臨時表保存中間結果,常用於GROUP BY 和 ORDER BY操作中,一般看到它說明查詢需要優化了,就算避免不了臨時表的使用也要儘量避免硬盤臨時表的使用。
Not exists MYSQL優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標準的行, 就不再搜索了。
Using index 說明查詢是覆蓋了索引的,不需要讀取數據文件,從索引樹(索引文件)中即可獲得信息。如果同時出現using where,表明索引被用來執行索引鍵值的查找,沒有using where,表明索引用來讀取數據而非執行查找動作。這是MySQL服務層完成的,但無需再回表查詢記錄。
Using index condition 這是MySQL 5.6出來的新特性,叫做“索引條件推送”。簡單說一點就是MySQL原來在索引上是不能執行如like這樣的操作的,但是現在可以了,這樣減少了不必要的IO操作,但是隻能用在二級索引上。
Using where 使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。注意:Extra列出現Using where表示MySQL服務器將存儲引擎返回服務層以後再應用WHERE條件過濾。
Using join buffer 使用了連接緩存:Block Nested Loop,連接算法是塊嵌套循環連接;Batched Key Access,連接算法是批量索引連接
impossible where where子句的值總是false,不能用來獲取任何元組
select tables optimized away 在沒有GROUP BY子句的情況下,基於索引優化MIN/MAX操作,或者對於MyISAM存儲引擎優化COUNT(*)操作,不必等到執行階段再進行計算,查詢執行計劃生成的階段即完成優化。
distinct 優化distinct操作,在找到第一匹配的元組後即停止找同樣值的動作

四,show profile分析SQL

show profiles 用來展示SQL執行過程中消耗的時間

show databases;

use db01;

show tables;

select * from tb_item where id < 5;

select count(*) from tb_item;

執行完上述指令後,使用 show profiles 指令

在這裏插入圖片描述

通過show profile for query [query_id] 可以查看到指定queryid 的sql 執行過程中每個線程的狀態和消耗的時間

在這裏插入圖片描述

Sending data 狀態表示MySQL線程開始訪問數據行並把結果返回給客戶端,而不僅僅是返回個客戶端。由於在Sending data狀態下,MySQL線程往往需要做大量的磁盤讀取操作,所以經常是整各查詢中耗時最長的狀態。

也可以選擇all、cpu、block io 、context switch、page faults等查看相應的參數

show profile all query [query_id]

show profile cpu query [query_id]

show profile block io query [query_id]

show profile context switch query [query_id]

show profile page faults query [query_id]

五,索引的使用

數據準備:

create table `t_user` (
	`userid` varchar (100),
	`username` varchar (100),
	`nickname` varchar (50),
	`password` varchar (60),
	`status` varchar (1),
	`address` varchar (100),
	`createtime` datetime,
    primary key(`userid`)
)engine=innodb default charset=utf8mb4; 

insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('aaaa','USER001','撒旦','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('bbbb','USER002','徐盛','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('cccc','USER003','華生','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('dddd','USER004','張智','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('eeee','USER005','馬程','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('ffff','USER006','羅小','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('gggg','USER007','方店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('hhhh','USER008','小白','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('jjjj','USER009','千度','e10adc3949ba59abbe56e057f20f883e','2','北京市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('kkkk','USER010','浪方','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('llll','USER011','米魚','e10adc3949ba59abbe56e057f20f883e','1','西安市','2088-01-01 12:00:00');
insert into `t_user` (`userid`, `username`, `nickname`, `password`, `status`, `address`, `createtime`) values('mmmm','USER012','周家','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');


create index idx_user_username_sta_addr on t_user(username,status,address);


COMMIT;

1,全值匹配,對索引中所有列都指定具體值

這種情況,索引生效,執行率高

explain select * from t_user where username='華生' and status='1' and address='北京市';

在這裏插入圖片描述

2,最左前綴法則

如果索引了多列,要遵守最左前綴法則。指的是查詢從索引的最左前列開始,並且不跳過索引中的列。

explain select * from t_user where username='華生';
explain select * from t_user where username='華生' and status='1';
explain select * from t_user where username='華生' and status='1' and address='北京市';

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

違反最左前綴法則,索引會失效

explain select * from t_user where status='1'; 

在這裏插入圖片描述

explain select * from t_user where status='1' and address='北京市';

在這裏插入圖片描述

符合最左前綴法則但是隻有最左列生效,出現跳躍某一列

explain select * from t_user where username='華生'  and address='北京市';

在這裏插入圖片描述

3,範圍查詢右邊的列,不能使用索引

explain select * from t_user where username='華生' and status='1' and address='北京市';
explain select * from t_user where username='華生' and status>'1' and address='北京市';

在這裏插入圖片描述
在這裏插入圖片描述
username和status是走了索引的,但是address是沒有走索引的,範圍查詢的右邊的列都是不走索引的

4,不要再索引列上進行運算操作,索引將會失效

explain select * from t_user where SUBSTRING(username,0,1) = '生';

在這裏插入圖片描述

5,字符串不加單引號,造成索引失效(MySQL的查詢優化器,會自動的進行類型轉換,造成索引失效)

explain select * from t_user where username='華生' and status='1' ;
explain select * from t_user where username='華生' and status=1 ;

在這裏插入圖片描述

在這裏插入圖片描述
6,儘量使用覆蓋索引,避免使用select *
儘量使用覆蓋索引(只訪問索引的查詢,索引列完全包含查詢列),減少select *

1,explain select * from t_user where username='華生' and status='1' and address='北京市';
2,explain select username from t_user where username='華生' and status='1' and address='北京市';
3,explain select username,status from t_user where username='華生' and status='1' and address='北京市';
4,explain select username,status,address from t_user where username='華生' and status='1' and address='北京市';
#查詢列超出索引列,也會降低性能
5,explain select username,status,address,password,createtime from t_user where username='華生' and status='1' and address='北京市';

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

查詢列超出索引列

在這裏插入圖片描述

extra:
 	using index :使用覆蓋索引的時候就會出現
    using where:在查找使用索引的情況下,需要回表去查詢所需的數據
    using index condition:查找使用了索引,但是需要回表查詢數據
    using index ; using where:查找使用了索引,但是需要的數據都在索引列中能找到,所以不需要回表查詢數據

7,用or分割開的條件,如果or前的條件中的列索引,而後面的列中沒有索引,那麼涉及的索引都不會被用到

explain select * from t_user where username = '華生' and createtime = '2088-01-01 12:00:00';
explain select * from t_user where username = '華生' or createtime = '2088-01-01 12:00:00';

在這裏插入圖片描述

在這裏插入圖片描述

8,以%開頭的Like模糊查詢,索引失效。
如果僅僅是尾部模糊匹配,索引不會失效。如果是頭部模糊匹配,索引失效。

explain select * from t_user where username like '%華' ;
explain select * from t_user where username like '華%' ;

在這裏插入圖片描述

在這裏插入圖片描述

解決:通過覆蓋所引來解決

explain select username from t_user where username like '%華' ;

在這裏插入圖片描述

explain select username,status from t_user where username like '%華' ;

在這裏插入圖片描述

explain select username,status,address from t_user where username like '%華' ;

在這裏插入圖片描述

9,如果mysql評估使用索引比全表更慢,則不使用索引

當表中的某類數據特別多的時候,查詢此類數據,使用索引比全表還慢,則使不用索引

create index idx_address on t_user(address);
show index from t_user;
select * from t_user;

在這裏插入圖片描述

explain select * from t_user where address='北京市';

在這裏插入圖片描述

explain select * from t_user where address='西安市';

在這裏插入圖片描述

10, is NULL , is NOT NULL 有時索引失效。

原理是mysql評估使用索引比全表更慢,則不使用索引,如果走索引快,則走索引

例子:當數據庫中某個字段爲null的數據少,is null走索引,is not null不走索引,反之亦然

11,in 走索引,not in索引失效

explain select * from t_user where username in ('華生','小白');
explain select * from t_user where username not in ('華生','小白');

在這裏插入圖片描述
在這裏插入圖片描述

12,單列索引和複合索引

儘量使用符合索引,而少使用單列索引

創建複合索引:	
	create index idx_user_username_sta_addr on t_user(username,status,address);

就相當於創建了三個索引 : 
	name
	name + status
	name + status + address
	
創建單列索引:
	create index idx_user_username on t_user(username);
	create index idx_user_sta on t_user(status);
	create index idx_user_addr on t_user(address);
	
數據庫會選擇一個最優的索引來使用,並不會使用全部索引	

12 查看索引的使用情況

show status like 'Handler_read%';	

show global status like 'Handler_read%';

在這裏插入圖片描述

Handler_read_first:索引中第一條被讀的次數。如果較高,表示服務器正執行大量全索引掃描(這個值越低越好)。

Handler_read_key:如果索引正在工作,這個值代表一個行被索引值讀的次數,如果值越低,表示索引得到的性能改善不高,因爲索引不經常使用(這個值越高越好)。

Handler_read_next :按照鍵順序讀下一行的請求數。如果你用範圍約束或如果執行索引掃描來查詢索引列,該值增加。

Handler_read_prev:按照鍵順序讀前一行的請求數。該讀方法主要用於優化ORDER BY ... DESC。

Handler_read_rnd :根據固定位置讀一行的請求數。如果你正執行大量查詢並需要對結果進行排序該值較高。你可能使用了大量需要MySQL掃描整個表的查詢或你的連接沒有正確使用鍵。這個值較高,意味着運行效率低,應該建立索引來補救。

Handler_read_rnd_next:在數據文件中讀下一行的請求數。如果你正進行大量的表掃描,該值較高。通常說明你的表索引不正確或寫入的查詢沒有利用索引。

13,索引下推

#現有聯合索引(username,age)
select * from t_user where username like '華%' and age > 23

語句執行有兩種可能:

​ 1,根據聯合索引查詢所有滿足名稱以“華”開頭的索引,然後回表查詢出相應的全行數據,然後再篩選出滿足年齡大於23的用戶數據
​ 2,根據聯合索引查詢所有滿足名稱以“華”開頭的索引,然後直接再篩選出年齡大於23的索引,之後再回表查詢全行數據

第二種方式回表查詢的全行數據少,這就是索引下推,mysql默認啓用索引下推,可以修改參數控制

SET optimizer_switch = 'index_condition_pushdown=off';

六,SQL的一些優化

數據準備

CREATE TABLE `emp` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `age` int(3) NOT NULL,
  `salary` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4;

insert into `emp` (`id`, `name`, `age`, `salary`) values('1','zhang','25','2300');
insert into `emp` (`id`, `name`, `age`, `salary`) values('2','li','30','3500');
insert into `emp` (`id`, `name`, `age`, `salary`) values('3','yang','25','2800');
insert into `emp` (`id`, `name`, `age`, `salary`) values('4','zhou','36','3500');
insert into `emp` (`id`, `name`, `age`, `salary`) values('5','zhu','21','2200');
insert into `emp` (`id`, `name`, `age`, `salary`) values('6','chen','31','3300');
insert into `emp` (`id`, `name`, `age`, `salary`) values('7','wang','26','2700');
insert into `emp` (`id`, `name`, `age`, `salary`) values('8','yao','33','3500');
insert into `emp` (`id`, `name`, `age`, `salary`) values('9','feng','23','2400');
insert into `emp` (`id`, `name`, `age`, `salary`) values('10','lv','32','3100');
insert into `emp` (`id`, `name`, `age`, `salary`) values('11','cui','26','2900');
insert into `emp` (`id`, `name`, `age`, `salary`) values('12','xu','37','4500');

create index idx_emp_age_salary on emp(age,salary);

1,order by

(1)通過對返回數據進行排序,即using filesort,也就是filesort排序,所有不是通過索引直接返回排序結果的排序都是filesort排序

explain select * from emp order by age desc;

在這裏插入圖片描述

(2)通過有索引順序掃描直接返回有序數據,即using index,不需要額外排序,效率高

explain select id,age,salary from emp order by age desc;

在這裏插入圖片描述

(3)多字段的情況

# 均爲索引字段,或者一塊都有排序且排序順序相同
explain select id,age,salary from emp order by age ,salary ;
explain select id,age,salary from emp order by age desc,salary desc;

在這裏插入圖片描述

#排序順序和索引順序不同
explain select id,age,salary from emp order by salary  desc,age desc;
# 部分字段使用排序
explain select id,age,salary from emp order by age desc,salary ;
explain select id,age,salary from emp order by age ,salary desc;
# 排序順序不同
explain select id,age,salary from emp order by age asc,salary desc;

在這裏插入圖片描述

總結:儘量減少額外的排序,通過索引直接返回有序數據,where條件和oeder by使用相同的索引,並且order by的順序和索引順序相同,並且排序的順序也要相同,否則會有額外操作,出現filesort

那麼出現using filesort時候怎麼辦?

filesort的出現降低效率,通過合適的索引,可以減少filesort。但是有些查詢條件的限制不能讓filesort消失,那就需要加快filesort的排序操作,基於filesort,mysql有兩種算法

1,兩次掃描算法:首先根據條件去除排序字段和行指針信息,然後在排序區sort buff中排序,如果sort buffer不夠,則在臨時表 temporary table 中存儲排序結果。完成排序之後,再根據行指針回表讀取記錄,該操作可能會導致大量隨機I/O操作。

2,一次掃描算法:次性取出滿足條件的所有字段,然後在排序區 sort buffer 中排序後直接輸出結果集。排序時內存開銷較大,但是排序效率比兩次掃描算法要高

MySQL 通過比較系統變量 max_length_for_sort_data 的大小和Query語句取出的字段總大小, 來判定是否那種排序算法,如果max_length_for_sort_data 更大,那麼使用第二種優化之後的算法;否則使用第一種。

可以適當提高 sort_buffer_size 和 max_length_for_sort_data 系統變量,來增大排序區的大小,提高排序的效率。

2,group by

如果查詢包含 group by 但是用戶想要避免排序結果的消耗, 則可以執行order by null 禁止排序。

explain select age,count(*) from emp group by age order by null;

3,嵌套查詢

SELECT語句來創建一個單列的查詢結果,然後把這個結果作爲過濾條件用在另一個查詢中。使用子查詢可以一次性的完成很多邏輯上需要多個步驟才能完成的SQL操作,同時也可以避免事務或者表鎖死,並且寫起來也很容易。但是,有些情況下,子查詢是可以被更高效的連接(JOIN)替代。

 explain select * from t_user where id in (select user_id from user_role );

優化:

explain select * from t_user u , user_role ur where u.id = ur.user_id;

連接(Join)查詢之所以更有效率一些 ,是因爲MySQL不需要在內存中創建臨時表來完成這個邏輯上需要兩個步驟的查詢工作。

4,or

對於包含OR的查詢子句,如果要利用索引,則OR之間的每個條件列都必須用到索引 , 而且不能使用到複合索引; 如果沒有索引,則應該考慮增加索引。

5,分頁查詢

當查詢一個 limit 1000000,10 的數據時,僅僅返回1000000 - 1000010 的記錄,其他記錄丟棄,查詢排序的代價非常大 。

1,在索引上完成排序分頁操作,然後根據主鍵關聯回原表查詢所需要的其他列數據

explain select * from t_user u,(select id from t_user order by id limit 1000000,10) t where u.id = t.id  

2,把limit 查詢轉化爲某個位置的查詢(使用自增主鍵)

explain select * from t_user where id>1000000  limit 10

接(JOIN)替代。

 explain select * from t_user where id in (select user_id from user_role );

優化:

explain select * from t_user u , user_role ur where u.id = ur.user_id;

連接(Join)查詢之所以更有效率一些 ,是因爲MySQL不需要在內存中創建臨時表來完成這個邏輯上需要兩個步驟的查詢工作。

4,or

對於包含OR的查詢子句,如果要利用索引,則OR之間的每個條件列都必須用到索引 , 而且不能使用到複合索引; 如果沒有索引,則應該考慮增加索引。

5,分頁查詢

當查詢一個 limit 1000000,10 的數據時,僅僅返回1000000 - 1000010 的記錄,其他記錄丟棄,查詢排序的代價非常大 。

1,在索引上完成排序分頁操作,然後根據主鍵關聯回原表查詢所需要的其他列數據

explain select * from t_user u,(select id from t_user order by id limit 1000000,10) t where u.id = t.id  

2,把limit 查詢轉化爲某個位置的查詢(使用自增主鍵)

explain select * from t_user where id>1000000  limit 10
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章