標籤:資料庫 mysql 5.7 步驟 hive 使用者 back work data commit
支援多種儲存引擎是眾所周知的MySQL特性,也是MySQL架構的關鍵優勢之一。如果能夠理解MySQL Server與儲存引擎之間是怎樣通過API互動的,將大大有利於理解MySQL的核心基礎架構。本文將首先介紹MySQL的整體邏輯架構,然後分析MySQL的儲存引擎API並介紹如何編寫自己的MySQL儲存引擎。
MySQL邏輯架構
MySQL作為一個大型的網路程式、資料管理系統,架構非常複雜。大致畫出了其邏輯架構。
Connectors
MySQL首先是一個網路程式,其在TCP之上定義了自己的應用程式層協議。所以要使用MySQL,我們可以編寫代碼,跟MySQL Server建立TCP串連,之後按照其定義好的協議進行互動。當然這樣比較麻煩,比較方便的辦法是調用SDK,比如Native C API、JDBC、PHP等各語言MySQL Connector,或者通過ODBC。但通過SDK來訪問MySQL,本質上還是在TCP串連上通過MySQL協議跟MySQL進行互動。
Connection Management
每一個基於TCP的網路服務都需要管理用戶端連結,MySQL也不例外。MySQL會為每一個串連綁定一個線程,之後這個串連上的所有查詢都在這個線程中執行。為了避免頻繁建立和銷毀線程帶來開銷,MySQL通常會緩衝線程或者使用線程池,從而避免頻繁的建立和銷毀線程。
用戶端串連到MySQL後,在使用MySQL的功能之前,需要進行認證,認證基於使用者名稱、主機名稱、密碼。如果用了SSL或者TLS的方式進行串連,還會進行認證認證。
SQL Interface
MySQL支援DML(資料操作語言)、DDL(資料定義語言 (Data Definition Language))、預存程序、視圖、觸發器、自訂函數等多種SQL語言介面。
Parser
MySQL會解析SQL查詢,並為其建立文法樹,並根據資料字典豐富查詢文法樹,會驗證該用戶端是否具有執行該查詢的許可權。建立好文法樹後,MySQL還會對SQl查詢進行文法上的最佳化,進行查詢重寫。
Optimizer
文法解析和查詢重寫之後,MySQL會根據文法樹和資料的統計資訊對SQL進行最佳化,包括決定表的讀取順序、選擇合適的索引等,最終產生SQL的具體執行步驟。這些具體的執行步驟裡真正的資料操作都是通過預先定義好的儲存引擎API來進行的,與具體的儲存引擎實現無關。
Caches & Buffers
MySQL內部維持著一些Cache和Buffer,比如Query Cache用來緩衝一條Select語句的執行結果,如果能夠在其中找到對應的查詢結果,那麼就不必再進行查詢解析、最佳化和執行的整個過程了。
Pluggable Storage Engine
儲存引擎的具體實現,這些儲存引擎都實現了MySQl定義好的儲存引擎API的部分或者全部。MySQL可以動態安裝或移除儲存引擎,可以有多種儲存引擎同時存在,可以為每個Table設定不同的儲存引擎。儲存引擎負責在檔案系統之上,管理表的資料、索引的實際內容,同時也會管理運行時的Cache、Buffer、事務、Log等資料和功能。
MySQL 5.7.11預設支援的儲存引擎如下:
mysql> show engines;+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+| Engine | Support | Comment | Transactions | XA | Savepoints |+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES || MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO || MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO || BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO || MyISAM | YES | MyISAM storage engine | NO | NO | NO || CSV | YES | CSV storage engine | NO | NO | NO || ARCHIVE | YES | Archive storage engine | NO | NO | NO || PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO || FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
File System
所有的資料,資料庫、表的定義,表的每一行的內容,索引,都是存在檔案系統上,以檔案的方式存在的。當然有些儲存引擎比如InnoDB,也支援不使用檔案系統直接管理裸裝置,但現代檔案系統的實現使得這樣做沒有必要了。
在檔案系統之下,可以使用本地磁碟,可以使用DAS、NAS、SAN等各種儲存系統。
儲存引擎API
MySQL定義了一系列儲存引擎API,以支援外掛程式式儲存引擎架構。API以Handler類的虛函數的方式存在,可在程式碼程式庫下的./sql/handler.h中查看詳細資料,可在handler類的注釋中看到描述:
/** The handler class is the interface for dynamically loadable storage engines. Do not add ifdefs and take care when adding or changing virtual functions to avoid vtable confusion Functions in this class accept and return table columns data. Two data representation formats are used: 1. TableRecordFormat - Used to pass [partial] table records to/from storage engine 2. KeyTupleFormat - used to pass index search tuples (aka "keys") to storage engine. See opt_range.cc for description of this format. TableRecordFormat ================= [Warning: this description is work in progress and may be incomplete] The table record is stored in a fixed-size buffer: record: null_bytes, column1_data, column2_data, ... //篇幅原因,略去部分內容。*/class handler :public Sql_alloc{ //篇幅原因,不列出具體代碼。讀者可直接在源碼檔案./sql/handler.h中找到具體內容。}
下面我將分類描述部分儲存引擎API。
建立、開啟和關閉表
通過函數create來建立一個table:
/** *name:要建立的表的名字 *from:一個TABLE類型的結構,要建立的表的定義,跟MySQL Server已經建立好的tablename.frm檔案內容是匹配的 *info:一個HA_CREATE_INFO類型的結構,包含了用戶端輸入的CREATE TABLE語句的資訊*/int create(const char *name, TABLE *form, HA_CREATE_INFO *info);
通過函數open來開啟一個table:
/** mode包含以下兩種 O_RDONLY - Open read only O_RDWR - Open read/write*/int open(const char *name, int mode, int test_if_locked);
通過函數close來關閉一個table:
int close(void);
對錶加鎖
當用戶端調用LOCK TABLE時,通過external_lock函數加鎖:
int ha_example::external_lock(THD *thd, int lock_type)
全表掃描
//初始化全表掃描virtual int rnd_init (bool scan);//從表中讀取下一行virtual int rnd_next (byte* buf);
通過索引訪問table內容
//使用索引前調用該方法int ha_foo::index_init(uint keynr, bool sorted) //使用索引後調用該方法int ha_foo::index_end(uint keynr, bool sorted)//讀取索引第一條內容int ha_index_first(uchar * buf);//讀取索引下一條內容int ha_index_next(uchar * buf);//讀取索引前一條內容int ha_index_prev(uchar * buf);//讀取索引最後一條內容int ha_index_last(uchar * buf);//給定一個key基於索引讀取內容int index_read(uchar * buf, const uchar * key, uint key_len, enum ha_rkey_function find_flag)
交易處理
//開始一個事務int my_handler::start_stmt(THD *thd, thr_lock_type lock_type)//復原一個事務int (*rollback)(THD *thd, bool all); //提交一個事務int (*commit)(THD *thd, bool all);
如何編寫自己的儲存引擎
在MySQL的官方文檔上,有對於編寫自己的儲存引擎的指導文檔,連結如下。
作為編寫自己儲存引擎的開始,你可以查看MySQL源碼庫中的一個EXAMPLE儲存引擎,它實現了必須要實現的儲存引擎API,可以通過複製它們作為編寫我們自己儲存引擎的開始:
sed -e s/EXAMPLE/FOO/g -e s/example/foo/g ha_example.h > ha_foo.hsed -e s/EXAMPLE/FOO/g -e s/example/foo/g ha_example.cc > ha_foo.cc
MySQL的多儲存引擎架構