1. 程式人生 > >mysql索引之三:索引使用注意規則(索引失效--存在索引但不使用索引)*

mysql索引之三:索引使用注意規則(索引失效--存在索引但不使用索引)*

使用索引時,有以下一些技巧和注意事項:

(1)越小的資料型別通常更好:越小的資料型別通常在磁碟、記憶體和CPU快取中都需要更少的空間,處理起來更快。
(2)簡單的資料型別更好:整型資料比起字元,處理開銷更小,因為字串的比較更復雜。在MySQL中,應該用內建的日期和時間資料型別,而不是用字串來儲存時間;以及用整型資料型別儲存IP地址。
(3)儘量避免NULL:應該指定列為NOT NULL,除非你想儲存NULL。在MySQL中,含有空值的列很難進行查詢優化,因為它們使得索引、索引的統計資訊以及比較運算更加複雜。你應該用0、一個特殊的值或者一個空串代替空值。
(4)索引不會包含有NULL值的列。

但是如果是同樣的sql如果在之前能夠使用到索引,那麼現在使用不到索引,以下幾種主要情況:

1. 隨著表的增長,where條件出來的資料太多,大於15%,使得索引失效(會導致CBO計算走索引花費大於走全表)

2. 統計資訊失效      需要重新蒐集統計資訊

3. 索引本身失效      需要重建索引

下面是一些不會使用到索引的原因
索引失效
1) 沒有查詢條件,或者查詢條件沒有建立索引;
2) 在查詢條件上沒有使用引導列
3) 查詢的數量是大表的大部分,應該是30%以上。 
4) 索引本身失效 
5) 查詢條件使用函式在索引列上(見12) 
6) 對小表查詢 
7) 提示不使用索引 
8) 統計資料不真實 
9) CBO計算走索引花費過大的情況。其實也包含了上面的情況,這裡指的是表佔有的block要比索引小。 


10)隱式轉換導致索引失效.這一點應當引起重視.也是開發中經常會犯的錯誤. 由於表的欄位tu_mdn定義為varchar2(20), 
但在查詢時把該欄位作為number型別以where條件傳給mysql,這樣會導致索引失效. 
錯誤的例子:select * from test where tu_mdn=13333333333; 
正確的例子:select * from test where tu_mdn='13333333333'; 
11)對索引列進行運算導致索引失效,我所指的對索引列進行運算包括(+,-,*,/,! 等) 
錯誤的例子:select * from test where id-1=9; 
正確的例子:select * from test where id=10; 
12)使用mysql內部函式導致索引失效.對於這樣情況應當建立基於函式的索引. 

錯誤的例子:select * from test where round(id)=10; 
說明,此時id的索引已經不起作用了 正確的例子:首先建立函式索引, 
create index test_id_fbi_idx on test(round(id)); 
然後 select * from test where round(id)=10; 這時函式索引起作用了


13)如果MySQL估計使用索引比全表掃描更慢,則不使用索引。例如如果列key_part1均勻分佈在1到100之間,查詢時使用索引就不是很好

mysql>select * from table_name where key_part1>1 and key_part<90;

14)如果使用MEMORY/HEAP表並且where條件中不使用“=”進行索引列,那麼不會用到索引Heap表只有在“=”的條件下會使用索引。因為用的是雜湊索引。

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

mysql> show index from test1\G;
*************************** 1. row ***************************
        Table: test1
   Non_unique: 1
     Key_name: inx_id_name
 Seq_in_index: 1
  Column_name: name
    Collation: A
  Cardinality: 552589
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
*************************** 2. row ***************************
        Table: test1
   Non_unique: 1
     Key_name: inx_id_name
 Seq_in_index: 2
  Column_name: id
    Collation: A
  Cardinality: 567855
     Sub_part: NULL
       Packed: NULL
         Null: 
   Index_type: BTREE
      Comment: 
Index_comment: 
2 rows in set (0.00 sec)

ERROR: 
No query specified

mysql> 

從上面可以發現只有name和id列上面有索引。來看如下的執行計劃。

mysql> explain extended select * from test1 where name='name100' or dept='dept100';
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | test1 | NULL       | ALL  | inx_id_name   | NULL | NULL    | NULL | 769014 |    19.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 2 warnings (0.00 sec)

mysql>

16)如果將要使用的索引列不是複合索引列表中的第一部分,則不會使用索引

如下例子:可見雖然在id上面建有複合索引,但是由於id不是索引的第一列,那麼在查詢中這個索引也不會被MySQL採用。

mysql> explain select * from test1 where id=1;
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | test1 | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 787947 |    10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql>

17)如果like是以%開始,可見雖然在name上面建有索引,但是由於where 條件中like的值的“%”在第一位了,那麼MySQL也會採用這個索引。

如果WHERE子句的查詢條件裡使用了比較操作符LIKE和REGEXP,MYSQL只有在搜尋模板的第一個字元不是萬用字元的情況下才能使用索引。比如說,如果查詢條件是LIKE 'abc%',MYSQL將使用索引;如果條件是LIKE '%abc',MYSQL將不使用索引。

18)獨立的列(對列變數需要計算(聚合運算、型別轉換等))

獨立的列是指索引列不能是表示式的一部分,也不是是函式的引數。例如以下兩個查詢無法使用索引:

1)表示式:  select actor_id from sakila.actor where actor_id+1=5;

2)函式引數:select ... where TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col)<=10;應該把列計算轉換成常量計算。

示例:

如果列型別是字串,但在查詢時把一個數值型常量賦值給了一個字元型的列名name,那麼雖然在name列上有索引,但是也沒有用到。

mysql> explain select * from company2 where name=294\G 
*************************** 1. row *************************** 
id: 1 
select_type: SIMPLE 
table: company2 
type: ALL 
possible_keys: ind_company2_name 
key: NULL 
key_len: NULL 
ref: NULL 
rows: 1000 
Extra: Using where 
1 row in set (0.00 sec)

而下面的sql語句就可以正確使用索引。

mysql> explain select * from company2 where name name=294'\G 
*************************** 1. row *************************** 
id: 1 
select_type: SIMPLE 
table: company2 
type: ref 
possible_keys: ind_company2_name 
key: ind_company2_name 
key_len: 23 
ref: const 
rows: 1 
Extra: Using where 
1 row in set (0.00 sec)

19).在JOIN操作中(需要從多個數據表提取資料時),MYSQL只有在主鍵和外來鍵的資料型別相同時才能使用索引,否則即使建立了 索引也不會使用

20).在ORDER BY操作中,MYSQL只有在排序條件不是一個查詢條件表示式的情況下才使用索引。儘管如此,在涉及多個數據表的查詢裡,即使有索引可用,那些索引在加快ORDER BY操作方面也沒什麼作用。

21).不要給“性別”增加索引。如果某個資料列裡包含著許多重複的值,就算為它建立了索引也不會有很好的效果。比如說,如果某個資料列裡包含了淨是些諸如“0/1”或“Y/N”等值,就沒有必要為它建立一個索引。

簡單的說吧,不需要,因為性別,就兩個值男與女(人妖不算,呵)。為這兩個值建立索引是不值得的,因為無論多少條記錄,建立性別的索引,最多讓你的語句少檢索一半。但與建立索引帶來的損失比,撿芝麻丟西瓜。(可能不準確,但大意如些)。

打個比方,資料庫就好比一本新華字典,我們查資料時,可以根據拼音來查,字在字典的排序是根據拼音來排序的,我們要查一個字,可以根據拼音很快就能查到我們要查的字,這就叫作聚集索引!換句話說,聚集索引就是按照物理排序的,也因為是按物理排序的,所以一張表只能有一個聚集索引,也是最快的索引。當然,我們也可以根據部首來查,但是這種查詢必須先查詢到部首,然後再到檢索表查到那麼字,最後才能查到我們需要的字,你沒辦法像拼音查法一樣翻翻字典就可以查到,這就叫作普通索引。普通索引可以有多個。 

假如一本字典裡全是"男"和"女"兩個字,那麼在檢索表裡也有很多個"男"和"女",這對查詢幫助不大。

22).如果對大的文字進行搜尋,使用全文索引而不使用like“%...%”.

23).如果列名是索引,使用column_name is null將使用索引。

如下

mysql> explain select * from company2 where name is null\G 
*************************** 1. row *************************** 
id: 1 
select_type: SIMPLE 
table: company2 
type: ref 
possible_keys: ind_company2_name 
key: ind_company2_name 
key_len: 11 
ref: const 
rows: 1 
Extra: Using where 
1 row in set (0.00 sec)

24).不使用NOT IN和<>操作
NOT IN和<>操作都不會使用索引將進行全表掃描。NOT IN可以NOT EXISTS代替,id<>3則可使用id>3 or id<3來代替。

25).排序的索引問題
mysql查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。因此資料庫預設排序可以符合要求的情況下不要使用排序操作;儘量不要包含多個列的排序,如果需要最好給這些列建立複合索引。

26).使用短索引
對串列進行索引,如果可能應該指定一個字首長度。例如,如果有一個CHAR(255)的列,如果在前10個或20個字元內,多數值是惟一的,那麼就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁碟空間和I/O操作。

27).索引不會包含有NULL值的列
只要列中包含有NULL值都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此複合索引就是無效的。所以我們在資料庫設計時不要讓欄位的預設值為NULL。

 28).使用ENUM而不是字串

ENUM儲存的是TINYINT,別在列舉中搞一些“中國”“北京”“技術部”這樣的字串,字串空間又大,效率又低。

三、索引分析方法

3.1檢視索引使用情況

如果索引正在工作,Handler_read_key的值將很高,這個值代表了一個行被索引值讀的次數。

Handler_read_rnd_next的值高則意味著查詢執行低效,並且應該建立索引補救。

mysql> show status like 'Handler_read%'; 
+-----------------------+--------+
| Variable_name         | Value  |
+-----------------------+--------+
| Handler_read_first    | 9      |
| Handler_read_key      | 16     |
| Handler_read_last     | 0      |
| Handler_read_next     | 680908 |
| Handler_read_prev     | 0      |
| Handler_read_rnd      | 0      |
| Handler_read_rnd_next | 935519 |
+-----------------------+--------+
7 rows in set (0.00 sec)

mysql> 

3.2兩個簡單實用的優化方法:

分析表的語法如下:(檢查一個或多個表是否有錯誤)

mysql> CHECK TABLE tbl_name[,tbl_name] …[option] …option = 
{ QUICK | FAST | MEDIUM| EXTENDED | CHANGED} 
mysql> check table sales; 
+--------------+-------+----------+----------+ 
| Table | Op | Msg_type | Msg_text | 
+--------------+-------+----------+----------+ 
| sakila.sales | check | status | OK | 
+--------------+-------+----------+----------+ 
1 row in set (0.01 sec)

優化表的語法格式:

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [,tbl_name]
如果已經刪除了表的一大部分,或者如果已經對含有可變長度行的表進行了很多的改動,則需要做定期優化。這個命令可以將表中的空間碎片進行合併,但是此命令只對MyISAM、BDB和InnoDB表起作用。

mysql> optimize table sales; 
+--------------+----------+----------+----------+ 
| Table | Op | Msg_type | Msg_text | 
+--------------+----------+----------+----------+ 
| sakila.sales | optimize | status | OK | 
+--------------+----------+----------+----------+ 
1 row in set (0.05 sec)

相關推薦

mysql索引索引使用注意規則索引失效--存在索引使用索引*

使用索引時,有以下一些技巧和注意事項: (1)越小的資料型別通常更好:越小的資料型別通常在磁碟、記憶體和CPU快取中都需要更少的空間,處理起來更快。(2)簡單的資料型別更好:整型資料比起字元,處理開銷更小,因為字串的比較更復雜。在MySQL中,應該用內建的日期和時間資料型別,而不是用字串來儲存時間;以及用整

RabbitMQ系列教程發布/訂閱Publish/Subscribe

mqc 標題 整合 參數 cti 事情 return 控制臺 run (本教程是使用Net客戶端,也就是針對微軟技術平臺的) 在前一個教程中,我們創建了一個工作隊列。工作隊列背後的假設是每個任務會被交付給一個【工人】。在這一部分我們將做一些完全不同的事情--我們將向多個

設計模式單例模式餓漢式與懶漢式

//保證類在記憶體中只有一個物件 package com.xjh.demo.designpattern.pattern3; public class Student { private Student(){ } //懶漢式 priva

Linux作業系統備份通過二進位制拷貝dd方式實現Linux作業系統資料的備份

今天我們介紹另外一種粗曠,但是相對簡單的備份方法:通過dd命令二進位制拷貝方式備份作業系統資料。dd拷貝的方式不能線上實施,因為dd是二進位制的塊拷貝,若拷貝過程中有寫檔案操作,會導致檔案系統不一致(如某個節點建立到一半被dd拷貝走了),因此,這種方式必須進入記憶體操作系的單使用者模式下操作,實施

hadoop初識搭建hadoop環境配置HDFS,Yarn及mapreduce 執行在yarn上及種執行模式本地模式,偽分散式和分散式介

--===============安裝jdk(解壓版)================== --root 使用者登入 --建立檔案層級目錄    /opt下分別 建 modules/softwares/datas/tools 資料夾 --檢視是否安裝jdk    rpm -

WIN32介面開發DUI雛形開發

前言:這部分涉及工程比較大,所以我打算分開為兩篇來寫,第一篇完成基本框架的構建,第二篇新增上EVENT和NOTIFY機制。 完成目標:仿照DirectUI,完成一個基本雛形,開發一個佈局控制元件(Dialog),和一個按鈕控制元件(Button),通過XML來佈局窗體,最後

RabbitMQ指南釋出/訂閱模式Publish/Subscribe

在上一章中,我們建立了一個工作佇列,工作佇列模式的設想是每一條訊息只會被轉發給一個消費者。本章將會講解完全不一樣的場景: 我們會把

mysql索引組合索引中選擇合適的索引列順序

組合索引(concatenated index):由多個列構成的索引,如create index idx_emp on emp(col1, col2, col3, ……),則我們稱idx_emp索引為組合索引。 在組合索引中有一個重要的概念:引導列(leading column),在上面的例子中,col1列

lucene全文搜尋生成索引欄位,建立索引文件索引欄位加權基於lucene5.5.3

前言:上一章中我們已經實現了索引器的建立,但是我們沒有索引文件,本章將會講解如何生成欄位、建立索引文件,給欄位加權以及儲存文件到索引器目錄 一、建立索引文件 一個索引目錄可以放多個索引文件,每個索引

Lucene學習總結Lucene的索引檔案格式(2)

浪費了“黃金五年”的Java程式設計師,還有救嗎? >>>   

MYSQL 學習筆記記錄整理子查詢

進行 測試 匹配 應該 因此 order 輸出 lec pro 1、利用子查詢進行過濾 eg:假如需要列出訂購物品TNT2的所有客戶,具體步驟: 檢索包含物品TNT2的所有訂單編號 檢索具有前一步驟列出的訂單編號的所有客戶的ID 檢索前一步驟返回的所有客戶ID的客戶信息 上

MySQL基礎語法join語法

join語法:表與表關聯 join 用於多表中欄位之間的聯絡 JOIN 按照功能大致分為如下三類: INNER JOIN(內連線,或等值連線):取得兩個表中存在連線匹配關係的記錄。 LEFT JOIN(左連線):取得左表(table1)完全記錄,即是右表(ta

ORACLE PL/SQL程式設計詳解PL/SQL流程控制語句(規則,不成方圓)

DECLARE    v_first_name employees.first_name%TYPE;    v_job_id employees.job_id%TYPE;    v_salary employees.salary%TYPE;    v_sal_raise NUMBER(3,2); B

Docker下MySQL主從三部曲binlog日誌引數實戰

本章是《Docker下MySQL主從三部曲》的終篇,前面的章節我們能夠製作映象來搭建主從同步環境,本章我們來觀察binlog引數MASTER_LOG_POS;關於從庫同步的設定在設定從庫同步的時候一般會使用以下SQL:CHANGE MASTER TO MASTER_HOST=

VCSA 6.5 HA配置 準備工作

vmware vcenter ha 高可用 vcsa 接著上一篇文章部署完成VCSA 6.5後,還需要做一些準備工作才能開啟高可用功能,本篇文章主要就講述如何為vCenter 高可用進行準備工作配置vCenter HA網絡從vCenter HA的架構圖中可以看出對於vCenter HA的高

Linux學習文件夾系統的結構和相對絕對路徑

sharp 二進制 沒有 數據 csharp pan 用戶 ont 臨時 理解每個目錄的作用 bin   二進制文件 boot   系統的啟動文件、內核 dev   設備文件 etc   配置文件 home  用戶的家目錄 lib    鏈接庫文件  l

MYSQL學習筆記日期和時間函數

div content minute name top fonts table hmm 指定 MYSQL學習筆記三:日期和時間函數 1. 獲取當前日期的函數和獲取當前時間的函數 /*獲取當前日期的函數和獲取當前時間的函數。將日期以‘YYYY-MM-DD‘或者’YYYYM

OSPF詳解OSPF LSA詳解

ospf lsa詳解 forwarding address OSPF LSA詳解OSPF V2版本中常用的主要有6類LSA,分別是Router-LSA、Network-LSA、Network-summary-LSA、ASBR-summary-LSA、AS-External-LSA、NSSA-LSA,接

Django運維後臺的搭建用url去精細定制與反向解析

django 反向解析 參數傳遞 url指向 上一篇文章裏,我們做了一個alionlineecs(阿裏雲線上環境服務器)的添加界面,但是要知道我們的計劃裏是有六個分支的,而alionlineecs僅僅是其中之一,要是每一個都這麽寫的話,那麽views.py肯定又臭又長,充滿了大量的復制片段。對

camera攝像原理色溫和自動白平衡【轉】

mil gho 實現 技術分享 處理 目標 紅旗 適應 如果 轉自:http://blog.csdn.net/ghostyu/article/details/7912863 色溫的定義:將黑體從絕對零度開始加溫,溫度每升高一度稱為1開氏度(用字母K表示),當溫度升高到一定