mysql數據庫索引和引擎


1. 數據庫索引

  1.1 索引作用

    當我們在數據庫表中查詢數據時,若沒有索引,會逐個遍歷表格中的所有記錄,表格中數據記錄量大時很耗時。建立索引就像創建目錄一樣,直接通過索引找到數據存儲位置,加快查找。例如:有一張person表,其中有2W條記錄,記錄着2W個人的信息。有一個Phone的字段記錄每個人的電話號碼,現在想要查詢出電話號碼為xxxx的人的信息。

      如果沒有索引,那么將從表中第一條記錄一條條往下遍歷,直到找到該條信息為止。

         如果有了索引,那么會將該Phone字段,通過一定的方法進行存儲,好讓查詢該字段上的信息時,能夠快速找到對應的數據,而不必在遍歷2W條數據了。其中MySQL中的索引的存儲類型有兩種:BTREE、HASH。 也就是用樹或者Hash值來存儲該字段,要知道其中詳細是如何查找的,就需要會算法的知識了。

    但索引也不是越多越好,因為創建的索引也需要占用空間,而且需要維護索引,因此沒必要為所有字段創建索引,對於經常需要查詢,或數據記錄很多的字段可以創建索引。

  1.2 索引分類(index或key)

    索引是在存儲引擎中實現的,也就是說不同的存儲引擎,會使用不同的索引

        MyISAM和InnoDB存儲引擎:只支持BTREE索引, 也就是說默認使用BTREE,不能夠更換

        MEMORY/HEAP存儲引擎:支持HASH和BTREE索引

    索引我們分為四類來講 單列索引(普通索引,唯一索引,主鍵索引)、組合索引、全文索引、空間索引、

      單列索引:一個索引只包含單個列,但一個表中可以有多個單列索引

          普通索引, INDEX:MySQL中基本索引類型,沒有什么限制,允許在定義索引的列中插入重復值和空值,純粹為了查詢數據更快一點。

          唯一索引,UNIQUE :索引列中的值必須是唯一的,但是允許為空值,   

          主鍵索引, PRIMARY KEY:是一種特殊的唯一索引,不允許有空值。         

      組合索引: 在表中的多個字段組合上創建的索引,只有在查詢條件中使用了這些字段的左邊字段時,索引才會被使用,使用組合索引時遵循最左前綴集合。

      全文索引 FULLTEXT :只有在MyISAM引擎上才能使用 (MySQL 5.6版本的InnoDB 開始支持全文索引),只能在CHAR,VARCHAR,TEXT類型字段上使用全文索引,介紹了要求,說說什么是全文索引,就是在一堆文字中,通過其中的某個關鍵字等,就能找到該字段所屬的記錄行.

      空間索引 SPATIAL :  只有在MyISAM引擎上才能使用(MySQL 5.7版本的InnoDB 開始支持)空間索引是對空間數據類型(坐標,地理位置等)的字段建立的索引,MySQL中的空間數據類型有四種,GEOMETRY、POINT、LINESTRING、POLYGON。創建空間索引的列,必須將其聲明為NOT NULL

   另外索引也可以分為聚集索引和非聚集索引:

     聚集(clustered)索引:數據行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同,一個表中只能擁有一個聚集索引。(即主鍵索引)

     非聚集索引(輔助索引):該索引中索引的邏輯順序與磁盤上行的物理存儲順序不同,一個表中可以擁有多個非聚集索引。(包括普通索引,唯一索引,全文索引等)

   1.3 索引操作

       1.3.1 創建索引(create index):  (創建索引后,通過SHOW CREATE TABLE tbname;能查看)

     下面命令給titles表中的title列增加索引 (索引名稱為idxtitle,未命名時默認為該字段名稱),有三種方式如下:

              1,創建表格時指定:

              CREATE TABLE titles(

            title varchar(100),

              publID INT,

              INDEX idxtitle (title)

          );

        2,創建索引: CREATE INDEX idxtitle ON titles(title);

        3,修改表設計,添加索引: ALTER TABLE titles ADD INDEX idxtitle (title);

           1.3.2增加不同的索引

        ALTER TABLE tablename ADD PRIMARY KEY (indexcols..);     不要寫索引名稱

        ALTER TABLE  tablename ADD INDEX [indexname] (indexcols..);

        ALTER TABLE tablename ADD UNIQUE [indexname] (indexcols..);

        ALTER TABLE tablename ADD FULLTEXT [indexname] (indexcols..);

        ALTER TABLE  tablename ADD INDEX [indexname] (indexcols1,indexcols2);   為indexcols1,indexcols2兩列創建組合索引

            1.3.3刪除索引:

        ALTER TABLE tablename DROP PRIMARY KEY ;

        ALTER TABLE  tablename DROP INDEX [indexname] ;

        DROP indexname ON table_name;

      1.3.4查看索引:

        SHOW INDEX FROM table_name;

        SHOW CREATE TABLE table_name;

        DESC table_name

      1.3.5 索引創建示例:   

1 普通索引:加速查找功能

創建表時定義索引
CREATE TABLE user(
    nid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(32) NOT NULL,
    age INT NOT NULL,
    email VARCHAR(64) NOT NULL,
    index n_index (name)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

創建表后添加索引
CREATE INDEX a_index ON user(age);
查看索引
SHOW INDEX FROM user;
刪除索引
DROP INDEX a_index ON user;

注意:對於創建索引時如果是BLOB 和 TEXT 類型,必須指定length。
create index ix_extra on in1(extra(32));

2.唯一索引功能:加速查找和唯一約束(可以為null)
CREATE TABLE user(
    nid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(32) NOT NULL,
    age INT NOT NULL,
    email VARCHAR(64) NOT NULL,
    UNIQUE n_index (name)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE INDEX a_index ON user(age);

SHOW INDEX FROM user;

DROP INDEX a_index ON user;

3. 主鍵索引功能:加速查找和唯一約束(不可為null),特殊的唯一索引
-- CREATE TABLE user(
--     nid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
--     name VARCHAR(32) NOT NULL,
--     age INT NOT NULL,
--     email VARCHAR(64) NOT NULL,
-- )ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 方式二
CREATE TABLE user(
    nid INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(32) NOT NULL,
    age INT NOT NULL,
    email VARCHAR(64) NOT NULL,
    PRIMARY key (nid)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

-- 創建和刪除
ALTER TABLE user ADD PRIMARY KEY(name);
ALTER TABLE user DROP PRIMARY KEY;
ALTER TABLE user MODIFY nid INT,DROP PRIMARY KEY;

4.組合索引:組合索引是將n個列組合成一個索引
其應用場景為:頻繁的同時使用n列來進行查詢,如:where name = 'zack' and password = "2222222"

CREATE INDEX com_index ON user(name,age);
組合索引有最左前綴性,對於上述組合索引,查詢時:
查詢:
    name and email  -- 使用索引
    name            -- 使用索引
    email           -- 不使用索引
注意:對於同時搜索n個條件時,組合索引的性能好於多個單一索引合並。
四種索引操作示例

   1.4 索引性能測試:

     先創建person表格,通過存儲過程插入5000條數據   

--創建表 

CREATE TABLE person(id INT, name VARCHAR(16));

--存儲過程 (創建函數,delimiter $$:修改終止符號為$$)   

delimiter $$

CREATE PROCEDURE autoinsert()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE(i<5000) DO
INSERT INTO person VALUES(i,'zack');
SET i=i+1;
END WHILE;
END$$

delimiter ;

--調用函數

CALL autoinsert();
創建person表

               無index時查詢:SELECT * FROM person WHERE id=4900;

      

               添加index后查詢:

          ALTER TABLE person ADD INDEX index_id (id);

          SELECT * FROM person WHERE id=4900;

          

   可以看出有索引時查詢時間變快。

  1.5.索引覆蓋

    索引覆蓋:建立索引后並不是所有的查詢都會通過索引表查詢,通過索引表的查詢稱為索引覆蓋。

    常見的不會覆蓋索引的情況:(通過explain語句分析,可以判斷是否覆蓋索引,但只是作為參考)

CREATE TABLE user(
    nid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(32) NOT NULL,
    age INT NOT NULL,
    email VARCHAR(64) NOT NULL,
    index n_index(name)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

show index from user;
name列為普通索引,id列為主鍵索引


不會覆蓋索引的情況:
1.以%開頭的模糊查詢:like "%cn"
    select * from user where name like '%cn';

2. 使用函數:
    select * from user where reverse(name) = 'zack';
    
3.OR語句中有一列不是索引列
    select * from user where id = 1 or email = '6734@qq.com';
    下列特殊情況:
    select * from user where id = 1 or email = '6734@qq.com' and name = 'zack'
        
4. 類型不一致
     (下面name列是字符串類型,傳入條件時必須用引號引起來,不然不會走索引)
        select * from user where name = 999;
        
5. 使用了!=
    select * from user where name != 'zack';
  特別的:如果是主鍵,則還是會走索引
        select * from user where id != 123;
                
6. 使用了>,< (有可能覆蓋索引,不同版本不一致)
        select * from user where name > 'zack';
    特別的:如果是主鍵或索引是整數類型,則還是會走索引
        select * from user where id > 123;
        select * from user where age > 123;
                
7. ORDER BY 語句根據索引列排序,選擇的映射如果不是索引,則不走索引
      select email from user order by name desc;
        下面會走索引:select name from user order by name desc;
    特別的:如果對主鍵排序,則還是走索引:
        select * from user order by id desc;
                
8.組合索引最左前綴原理
     如果組合索引為:(name,email)
    name and email       -- 使用索引
    name                 -- 使用索引
    email                -- 不使用索引
覆蓋索引

   1.6 索引數據結構

     (參考:http://blog.codinglabs.org/articles/theory-of-mysql-index.html)

     一般索引采用B+ Tree和B- Tree實現,MySQL的InnoDB和MyISAM都采用B+ Tree實現,但存儲細節上不一樣。

     MyISAM存儲引擎:MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址(葉節點data域)。

       主鍵索引(primary key):其結構如下,B+ Tree的葉子節點的key存放主鍵值,data存放主鍵值對應數據行的存儲地址,而非葉子節點key為主鍵值,不存儲data。查找時通過key從上往下找到葉子結點,如果key存在,拿到數據行存儲地址。

          輔助索引(secondary key):上圖中col1為主鍵,在col2上建立一個輔助索引,其結構如下,可以發現其結構和主鍵索引沒有區別,葉子節點data存放的也是數據行地址(不同之處在於主索引要求key是唯一的,而輔助索引的key可以重復)

     InnoDB存儲引擎InnoDB的數據文件本身就是索引文件,葉節點data域保存了完整的數據記錄

       主鍵索引:其結構如下,B+ Tree的葉子節點key存放主鍵值data存放完整的數據記錄。非葉子節點key為主鍵值,不存儲data。查找時通過key從上往下找到葉子結點,如果key存在,直接拿到數據。

       輔助索引:對於輔助索引的結構如下,與主鍵索引不同的是,葉節點的data存放存放主鍵索引的值,而不是地址,因此輔助索引進行檢索時需要檢索兩遍索引,首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄。

       通過上述結構發現,InnoDB數據文件即包含主鍵索引,所以InnoDB要求表必須有主鍵,如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作為主鍵,如果不存在這種列,則MySQL自動為InnoDB表生成一個隱含字段作為主鍵。而且不建議使用過長的字段作為主鍵,因為所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。另外,用非單調的字段作為主鍵在InnoDB中也不建議,因為InnoDB數據文件本身是一顆B+Tree,非單調的主鍵會造成在插入新記錄時數據文件為了維持B+Tree的特性而頻繁的分裂調整,十分低效,而使用自增字段作為主鍵則是一個很好的選擇。

2,mysql數據庫引擎

https://dev.mysql.com/doc/refman/5.7/en/storage-engines.html

   數據庫存儲引擎,是mysql用來處理SQL語句的組件,對每一個數據表格,創建時都需要指定一個數據庫引擎,mysql會使用該引擎來處理這個表格的相應操作,因此對於不同引擎的表格,SQL語句的處理結果和性能會不同。另外,對於一個數據庫中的表格,每個表格都可以指定不同的數據庫引擎。通過命令SHOW ENGINES;能查看mysql支持的數據庫引擎。主要有InnoDB,MyISAM, Memory, CSV, Archve, Blackhole等,常用的就是InnoDB,MyISAM, Memory。其中通過Create table 命令默認設置的引擎為InnoDB。

  2.1 設置數據表格引擎:

       創建表格時指定:CREATE TABLE titles(id INT, name VARCHAR(16)) ENGINE = InnoDB;

    創建后修改:ALTER TABLE titles ENGINE = InnoDB;

          (SET default_storage_engine=NDBCLUSTER; 設置默認的引擎)

  2.2 InnoDB特點

    https://dev.mysql.com/doc/refman/5.7/en/innodb-introduction.html

    InnoDB支持事務操作,即commit,rollback和crash-recovery;

    InnoDB支持行級鎖,即可以給一行數據上鎖;

    InnoDB支持外鍵關系約束;

 

      

  2.3 MyISAM特點

    https://dev.mysql.com/doc/refman/5.7/en/myisam-storage-engine.html

      MyISAM 適合讀取操作較多的數據表,其讀取速度較快;

    MyISAM支持表級鎖,可以給一張表上鎖;

    MyISAM支持全文索引;

    MyISAM 支持Gometry,Point等表示空間位置的數據類型;

          

   2.3 Memory:僅存在於內存中,多用於臨時表格(hash index)

3.ODBC和JDBC

  ODBC(open database connectivity): windows系統中數據庫系統的一個驅動,基於ODBC的軟件能夠通過ODBC驅動來操控數據庫中的數據。(如excel, access 能夠通過ODBC連接MySQL 數據庫,進行數據的增刪改查

  JDBC (java database connectivity):unix和Linux系統上數據庫系統的驅動。

 

參考博客:https://www.cnblogs.com/whgk/p/6179612.html

       http://www.cnblogs.com/yuanchenqi/articles/6357507.html

            MyISAM和InnoDB的區別:https://segmentfault.com/a/1190000008227211

     聚集索引與非聚集索引:https://www.cnblogs.com/s-b-b/p/8334593.html

        MySQL索引背后的數據結構及算法原理

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM