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表示),當溫度升高到一定