MySQL(四)

索引及執行計劃mysql

索引就比如一本書的目錄,它會讓你更快的找到內容
讓獲取的數據更有目的性,從而提升數據庫檢索數據的性能。linux

經常使用btree索引redis

 


索引基本管理:sql

desc 查看信息看key值有沒有全部信息數據庫

建立和刪除:
  alter table student add index idx_name(stu_name);     idx_name  索引的名字vim

    這是在表的列上建立索引
  緩存

  alter table student drop index idx_name;
或者服務器

  create index inx_name on stu(stu_name); 
  drop index inx_name on stu;elasticsearch

查詢索引設置
  desc student;函數

  show index from student;

用expain查看SQL的執行計劃
mysql> explain select id,name from test where name='oldboy'\G
explain select SQL_NO_CACHE * from test where name='oldboy'\G
SQL_NO_CACHE的做用是禁止緩存查詢結果。


主鍵索引: 惟1、非空
走主鍵索引的查詢效率是最高的,咱們儘可能每一個表有一個主鍵,而且未來查詢的時候計量以主鍵爲條件查詢

建表時 指定一個非空而且惟一的列爲主鍵

CREATE TABLE `test` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`name` char(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;

 

建表後

CREATE TABLE `test1` (
`id` int(4) NOT NULL,
`name` char(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
增長自增主鍵
  alter table test1 change id id int(4) primary key not null auto_increment;

 

前綴索引: 選列的前幾個字符做爲索引的查詢條件  來簡化索引
  create index index_name on student(stu_id(8));

查看索引爲前八個字符做爲條件

  show index from student;

聯合索引:
  where a女生 and b身高165 and c身材好

  index(a,b,c)

特色:前綴生效特性。

  a,ab,abc,ac 能夠走索引。
  b bc c 不走索引。

原則:把最經常使用來做爲條件查詢的列放在前面。

走索引
  select * from people where a='nv' and b>=165 and tizhong<=120;
  select * from people where a='nv' and b>=165;
  select * from people where a='nv';
  select * from people where a='nv' and tizhong<=120;

  以上查詢符合創建聯合索引

  alter table student add index minx(gender,age);


惟一性索引: 普通索引前面加上unique
  create unique index index_name on test(name);

-------------------------------------------------

explain 調取語句的執行計劃。

主要是判斷語句是否走索引


explain select stu_name,gender,age from student where gender='F' and age <20;

 


mysql> explain select name,gender,age from test where gender='F' and age <20;
+----+-------------+-------+-------+---------------+----------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-----------------------+
| 1 | SIMPLE    |     test | range | inx_test | inx_test | 7 | NULL | 1 | Using index condition |

 

 


type : 表示MySQL在表中找到所需行的方式,又稱「訪問類型」,

常見類型以下:

  ALL,index, range, ref, eq_ref, const, system, NULL

  從左到右,性能從最差到最好

ALL:
  Full Table Scan, MySQL將遍歷全表以找到匹配的行

  若是顯示ALL,說明查詢沒有走索引:

  一、語句自己的問題
  二、索引的問題,沒創建索引

index:Full Index Scan,index與ALL區別爲index類型只遍歷索引樹
  例子:
    explain select count(*) from stu ;

range:索引範圍掃描,對索引的掃描開始於某一點,返回匹配值域的行。
  顯而易見的索引範圍掃描是帶有between或者where子句裏帶有<,>查詢。
  where 條件中有範圍查詢或模糊查詢時
  > < >= <= between and in () or
  like 'xx%'

  當mysql使用索引去查找一系列值時,例如IN()和OR列表,也會顯示range(範圍掃描),固然性能上面是有差別的。


ref:使用非惟一索引掃描或者惟一索引的前綴掃描,返回匹配某個單獨值的記錄行

  where stu_name='xiaoming'

  explain select * from stu where stu_name='aa';

eq_ref:相似ref,區別就在使用的索引是惟一索引,對於每一個索引鍵值,表中只有一條記錄匹配,簡單來講,
  就是多表鏈接中使用primary key或者 unique key做爲關聯條件

  join條件使用的是primary key或者 unique key


const、system:當MySQL對查詢某部分進行優化,並轉換爲一個常量時,使用這些類型訪問。
  如將主鍵置於where列表中,MySQL就能將該查詢轉換爲一個常量

  explain select * from city where id=1;


NULL:MySQL在優化過程當中分解語句,執行時甚至不用訪問表或索引,
  例如從一個索引列裏選取最小值能夠經過單獨索引查找完成。


mysql> explain select name,population from city;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | city | ALL | NULL | NULL | NULL | NULL | 4188 | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+


Extra:

  Using temporary
  Using filesort
  Using join buffer

排序 order by ,group by ,distinct,排序條件上沒有索引
explain select * from city where countrycode='CHN' order by population;

在join 的條件列上沒有創建索引

 

-------------------------------------------------
1、數據庫索引的設計原則:

爲了使索引的使用效率更高,在建立索引時,必須考慮在哪些字段上建立索引和建立什麼類型的索引。
那麼索引設計原則又是怎樣的?

1.選擇惟一性索引
  惟一性索引的值是惟一的,能夠更快速的經過該索引來肯定某條記錄。
  例如,學生表中學號是具備惟一性的字段。爲該字段創建惟一性索引能夠很快的肯定某個學生的信息。
  若是使用姓名的話,可能存在同名現象,從而下降查詢速度。

  主鍵索引和惟一鍵索引,在查詢中使用是效率最高的。

2.爲常常須要排序、分組和聯合操做的字段創建索引
  常常須要ORDER BY、GROUP BY、DISTINCT和UNION等操做的字段,排序操做會浪費不少時間。
  若是爲其創建索引,能夠有效地避免排序操做。

 

3.爲常做爲查詢條件的字段創建索引
  若是某個字段常常用來作查詢條件,那麼該字段的查詢速度會影響整個表的查詢速度。所以,
  爲這樣的字段創建索引,能夠提升整個表的查詢速度。


  select count(DISTINCT population ) from city;  看population不重複的 有多少行
  select count(*) from city;                                     看總行數      看到不重複的行更多那就能夠吧這個列創建索引

 

4.儘可能使用前綴來索引
  若是索引字段的值很長,最好使用值的前綴來索引。例如,TEXT和BLOG類型的字段,進行全文檢索
  會很浪費時間。若是隻檢索字段的前面的若干個字符,這樣能夠提升檢索速度。

 

------------------------以上的是重點關注的,如下是能保證則保證的--------------------

5.限制索引的數目
  索引的數目不是越多越好。每一個索引都須要佔用磁盤空間,索引越多,須要的磁盤空間就越大。
  修改表時,對索引的重構和更新很麻煩。越多的索引,會使更新表變得很浪費時間。

 


6.儘可能使用數據量少的索引
  若是索引的值很長,那麼查詢的速度會受到影響。例如,對一個CHAR(100)類型的字段進行全文
  檢索須要的時間確定要比對CHAR(10)類型的字段須要的時間要多。

 

7.刪除再也不使用或者不多使用的索引
  表中的數據被大量更新,或者數據的使用方式被改變後,原有的一些索引可能再也不須要。數據庫管理
  員應當按期找出這些索引,將它們刪除,從而減小索引對更新操做的影響。

---------------------------------------------2、開發規範---------------------------------------------------------------

不走索引的狀況:
重點關注:
1) 沒有查詢條件,或者查詢條件沒有創建索引

  select * from tab; 全表掃描。
  select * from tab where 1=1;

在業務數據庫中,特別是數據量比較大的表。
是沒有全表掃描這種需求。

一、對用戶查看是很是痛苦的。
二、對服務器來說毀滅性的。


(1)select * from tab;

SQL改寫成如下語句:
selec * from tab order by price limit 10 須要在price列上創建索引

(2)
select * from tab where name='zhangsan' name列沒有索引

改:
一、換成有索引的列做爲查詢條件
二、將name列創建索引



2) 查詢結果集是原表中的大部分數據,應該是30%以上。

查詢的結果集,超過了總數行數30%,優化器以爲就沒有必要走索引了。

假如:tab表 id,name id:1-100w ,id列有索引

select * from tab where id>500000;


若是業務容許,可使用limit控制。

怎麼改寫 ?
結合業務判斷,有沒有更好的方式。若是沒有更好的改寫方案
儘可能不要在mysql存放這個數據了。放到redis裏面。


3) 索引自己失效,統計數據不真實

索引有自我維護的能力。
對於表內容變化比較頻繁的狀況下,有可能會出現索引失效。

 

4) 查詢條件使用函數在索引列上,或者對索引列進行運算,運算包括(+,-,*,/,! 等)
例子:
錯誤的例子:select * from test where id-1=9;
正確的例子:select * from test where id=10;


5)隱式轉換致使索引失效.這一點應當引發重視.也是開發中常常會犯的錯誤.
因爲表的字段tu_mdn定義爲varchar2(20),但在查詢時把該字段做爲number類型以where條件傳給數據庫,
這樣會致使索引失效. 錯誤的例子:select * from test where tu_mdn=13333333333;
正確的例子:select * from test where tu_mdn='13333333333';
------------------------
mysql> alter table tab add index inx_tel(telnum);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql>
mysql>
mysql>
mysql> desc tab;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| telnum | varchar(20) | YES | MUL | NULL | |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)


mysql> select * from tab where telnum='1333333';
+------+------+---------+
| id | name | telnum |
+------+------+---------+
| 1 | a | 1333333 |
+------+------+---------+
1 row in set (0.00 sec)

mysql> select * from tab where telnum=1333333;
+------+------+---------+
| id | name | telnum |
+------+------+---------+
| 1 | a | 1333333 |
+------+------+---------+
1 row in set (0.00 sec)

mysql> explain select * from tab where telnum='1333333';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tab | ref | inx_tel | inx_tel | 63 | const | 1 | Using index condition |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
1 row in set (0.00 sec)

mysql> explain select * from tab where telnum=1333333;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | tab | ALL | inx_tel | NULL | NULL | NULL | 2 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)


mysql> explain select * from tab where telnum=1555555;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | tab | ALL | inx_tel | NULL | NULL | NULL | 2 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from tab where telnum='1555555';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tab | ref | inx_tel | inx_tel | 63 | const | 1 | Using index condition |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
1 row in set (0.00 sec)

mysql>


------------------------

6)
<> ,not in 不走索引

EXPLAIN SELECT * FROM teltab WHERE telnum <> '110';
EXPLAIN SELECT * FROM teltab WHERE telnum NOT IN ('110','119');
------------
mysql> select * from tab where telnum <> '1555555';
+------+------+---------+
| id | name | telnum |
+------+------+---------+
| 1 | a | 1333333 |
+------+------+---------+
1 row in set (0.00 sec)

mysql> explain select * from tab where telnum <> '1555555';
-----
單獨的>,<,in 有可能走,也有可能不走,和結果集有關,儘可能結合業務添加limit
or或in 儘可能改爲union

EXPLAIN SELECT * FROM teltab WHERE telnum IN ('110','119');
改寫成:

EXPLAIN SELECT * FROM teltab WHERE telnum='110'
UNION ALL
SELECT * FROM teltab WHERE telnum='119'

-----------------------------------
7) like "%_" 百分號在最前面不走

EXPLAIN SELECT * FROM teltab WHERE telnum LIKE '31%' 走range索引掃描

EXPLAIN SELECT * FROM teltab WHERE telnum LIKE '%110' 不走索引


%linux%類的搜索需求,可使用elasticsearch


%linux培訓%

 

8) 單獨引用複合索引裏非第一位置的索引列.
列子:
複合索引:

DROP TABLE t1
CREATE TABLE t1 (id INT,NAME VARCHAR(20),age INT ,sex ENUM('m','f'),money INT);

ALTER TABLE t1 ADD INDEX t1_idx(money,age,sex);
DESC t1
SHOW INDEX FROM t1
走索引的狀況測試:
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30 AND sex='m';
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30 ;
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND sex='m'; ----->部分走索引
不走索引的:
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE age=20
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE age=30 AND sex='m';
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE sex='m';

 

存儲引擎查詢

 

 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

show engines;    查看支持的存儲引擎
show create table city;  查看錶的存儲引擎
show table status like 'city'\G 同上
select table_schema,table_name,engine from information_schema.tables where table_schema='world';    查詢world庫的全部表的存儲引擎
select table_schema,table_name,engine from information_schema.tables where table_schema='mysql';   同上
select table_schema,table_name,engine from information_schema.tables where engine='csv';                   查詢整個數據庫中 使用CSV引擎的表

 設置存儲引擎

 

一、在啓動配置文件中設置服務器存儲引擎:
  [mysqld]
  default-storage-engine=<Storage Engine>
二、使用 SET 命令爲當前客戶機會話設置:
  SET @@storage_engine=<Storage Engine>;
三、在 CREATE TABLE 語句指定:
  CREATE TABLE t (i INT) ENGINE = <Storage Engine>;

 

 

 

 

表空間:

 

共享表空間:主要存放系統元數據等
獨立表空間:主要存放用戶數據

 


共享表空間設置:

 

innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend

 

innodb_data_file_path=ibdata1:12M;ibdata2:50M:autoextend ----錯誤的配置XXX

 

innodb_data_file_path=ibdata1:76M;ibdata2:50M:autoextend -----正確的配置

 

 

 

 

 

 

----------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------

 

 

 

 

 

 

 

MySQL日誌管理

MySQL日誌——(2)錯誤日誌

 

配置方法:
  [mysqld]
  log-error=/data/mysql/mysql.log
查看配置方式:
  mysql> show variables like '%log%error%';
做用:
記錄mysql數據庫的通常狀態信息及報錯信息,是咱們對於數據庫常規報錯處理的經常使用日誌。

MySQL日誌——(3)通常查詢日誌
配置方法:
  [mysqld]
  general_log=on
  general_log_file=/data/mysql/server2.log
查看配置方式:
  show variables like '%gen%';
做用:
記錄mysql全部執行成功的SQL語句信息,能夠作審計用,可是咱們不多開啓

MySQL日誌——二進制日誌(2)
一、二進制日誌都記錄了什麼?
  已提交的數據記錄,以event的形式記錄到二進制文件中
二、二進制記錄格式有哪些?
  row:行模式,即數據行的變化過程,上圖中Age=19修改爲 Age=20的過程事件。
  statement:語句模式,上圖中將update語句進行記錄。
  mixed:以上二者的混合模式。
三、三總模式有什麼優缺點?
四、binlog的做用
  備份恢復、複製

二進制日誌的管理(1)
一、開啓二進制日誌
  set sql_log_bin=0 在會話級別修改成臨時關閉
  vi /etc/my.cnf
  log-bin=/data/mysql/mysql-bin 在全局打開binlog

  binlog_format=row

二、設置二進制日誌記錄格式(建議是ROW):
配置文件中修改:
  binlog-format=ROW
命令行修改
  mysql> SET GLOBAL binlog_format = 'STATEMENT';
  mysql> SET GLOBAL binlog_format = 'ROW';
  mysql> SET GLOBAL binlog_format = 'MIXED';
三、查看binlog設置
  show variables like '%binlog%';

四、binlog的刷新策略或叫同步策略

  sync_binlig=1   每次的事物提交都寫入磁盤

二進制日誌管理(2)
查詢二進制日誌文件
ls -l /data/mysql/mysql-bin*

mysql> SHOW BINARY LOGS;
+---------------+-----------+
| Log_name | File_size |
+---------------+-----------+
| binlog.000015 | 724935 |
| binlog.000016 | 733481 |

mysql> SHOW MASTER STATUS;
+---------------+----------+--------------+------------------+
|       File            | Position | Binlog_Do_DB   | Binlog_Ignore_DB |
+---------------+----------+--------------+------------------+
| binlog.000016 | 733481   | world_innodb     |      manual,mysql |

 

二進制日誌管理(3)
  獲取二進制日誌的內容及事件

二進制日誌管理(4)
  刷新二進制日誌
  flush logs
  截取二進制日誌
  mysqlbinlog --start-position= --stop-position= >a.sql
問題:
  一、什麼是事件?
  二、什麼是position ?

 

 

 

 


二進制日誌 實際操做

 

新建一個二進制日誌的路徑和文件並受權

mkdir /data/binlog -p
chown -R mysql.mysql /data/binlog

vim /etc/my.cnf

log-bin=/data/binlog
binlog_format=row
sync_binlog=1

 


show binary logs;                                    查看當前全部可用的二進制日誌信息
show binlog events in 'my-bin.000002'   看二進制文件的 信息
show master status;                                看當前正在使用的二進制日誌      

 

mysqlbinlog --base64-output=decode-rows -v my-bin.000002    

轉碼以decode-rows 打印二進制的內容

mysqlbinlog --start-position=120 --stop-position=721 my-bin.000002

截取二進制內容

mysqbinlog --start-position=340 --stop-position=721 my-bin.000002 >/tmp/binlog.sql

截取內容導入到文件

 

使用二進制日誌恢復數據

use lufei;

set sql_log_bin=0; 臨時關閉二進制日誌的記錄  而後進行恢復

source  /mysql/data/mysql-bin.000017    指定文件恢復

也能夠截取部分二進制文件內容進行恢復,跳過或避免恢復錯誤的操做

set sql_log_bin=0;

source /tmp/binlog.sql     選擇保存的截取部分  實時點恢復


flush logs;   刷新日誌/從新增長一個二進制文件

 

刪除二進制:
  默認狀況下,不會刪除舊的日誌文件。
  根據存在時間刪除日誌:
  SET GLOBAL expire_logs_days = 90;
  …或者…
  PURGE BINARY LOGS BEFORE now() - INTERVAL 3 day;  刪除三天之前的
  根據文件名刪除日誌:
  PURGE BINARY LOGS TO 'mysql-bin.000010';

  reset master;  清理全部的日誌
-------------------
MySQL的慢查詢日誌

功能:
  slow-log,記錄全部條件內的慢的SQL語句
  優化的一種工具日誌。幫咱們定位問題。
  是將mysql服務器中影響數據庫性能的相關SQL語句記錄到日誌文件
  經過對這些特殊的SQL語句分析,改進以達到提升數據庫性能的目的。

慢日誌設置:
  long_query_time    :  設定慢查詢的閥值,超出次設定值的SQL即被記錄到慢查詢日誌,缺省爲10s
  slow_query_log      :  指定是否開啓慢查詢日誌
  slow_query_log_file :  指定慢日誌文件存放位置,能夠爲空,系統會給一個缺省的文件host_name-slow.log
  min_examined_row_limit:查詢檢查返回少於該參數指定行的SQL不被記錄到慢查詢日誌
  log_queries_not_using_indexes: 不使用索引的慢查詢日誌是否記錄到索引

配置例子:
  slow_query_log=1 
  slow_query_log_file=/data/slow/slow.log
  long_query_time=0.5
  log_queries_not_using_indexes


 

 

 

處理慢日誌:
  mysqldumpslow命令 排序日誌內容

  mysqldumpslow -s c -t 10 /data/slow/slow.log
  mysqldumpslow -s at -t 10 /data/slow/slow.log


這會輸出記錄次數最多的10條SQL語句,
其中:
-s
是表示按照何種方式排序
c、t、l、r分別是按照記錄次數、時間、查詢時間、返回的記錄數來排序。
ac、at、al、ar,表示相應的倒敘。
-t
是top n的意思,即爲返回前面多少條的數據;

----------本身擴展
pt-query-diagest         percona-toolkit工具箱裏的
mysqlsla      

相關文章
相關標籤/搜索