對用戶來講,分區表是一個獨立的邏輯表,可是底層由多個物理子表組成。實現分區表的代碼其實是對一組底層表的句柄對象的封裝。對分區表的請求,都會經過句柄對象轉化成對存儲引擎的接口調用。node
分區的一個主要目的是將數據按照一個較粗的粒度分在不一樣的表中,這樣作能夠將相關數據存放在一塊兒,另外,若是想一次批量刪除整個分區的數據也會變的很方便。mysql
下面的場景中,分區能夠起到很是大的做用:算法
分區表自己也有一些限制:sql
分區表上的操做按照下面的操做邏輯進行:數據庫
雖然每一個操做都會「先打開並鎖住全部的底層表」,但這並非說分區表在處理過程當中是鎖住全表的,若是存儲引擎可以本身實現行級鎖,如InnoDB,則會在分區層釋放對應表鎖。這個加鎖和解鎖過程與普通InnoDB上的查詢相似。緩存
mysql支持多種分區表,咱們看到最多的是根據範圍進行分區,每一個分區存儲落在某個範圍的記錄,分區表達式能夠是列,也能夠是包含列的表達式。安全
create table sales(
order_date datetime not null,
-- other columns omitted
) engine=innodb partition by range(year(order_date)) (
partition p_2010 values less than (2010),
partition p_2011 values less than (2011),
partition p_2012 values less than (2012),
partition p_catchall values less than maxvalue
);
複製代碼
partition分區子句中可使用各類函數,但有一個要求,表達式返回的值要是一個肯定的整數,且不能是一個常數。服務器
mysql還支持鍵值,哈希和列表分區,這其中有些還支持子分區,不過咱們在生產環境中不多見到。網絡
咱們還看到的一些其餘的分區技術包括:mysql優化
假設咱們但願從一個很是大的表中查詢出一段時間的記錄,而這個表中包含了不少年的歷史數據,數據是按照時間排序的,例如但願查詢最近幾個月的數據,這大約有10億條記錄。 首先很確定:由於數據量巨大,確定不能在每次查詢的時候都掃描全表。考慮到索引在空間和維護上的消耗,也不但願使用索引。即便真的使用索引,你會發現數據並非按照想要的房市彙集的,並且會有大量的碎片產生,最終會致使一個查詢產生成千上萬的隨機I/O,應用程序也隨之僵死。 這時候有兩條路可選:讓全部的查詢都只在數據表上作順序掃描或者將數據表和索引所有都緩存在內存裏。
這裏須要再陳述一遍:在數據量大的時候,B-Tree索引就沒法起做用了。除非是索引覆蓋查詢,不然數據庫服務器須要根據索引掃描的結果回表,查詢全部符合條件的記錄,若是數據量巨大,浙江產生大量隨機I/O,隨之,數據庫的響應時間將達到不可接受的程度。 另外,索引維護的代價也很是高。
這正是分區要作的事情。理解分區時還能夠將其看成索引的最初形態,以代價很是小的房市定位到須要的數據在哪一片「區域」,在這篇區域中,你能夠作順序掃描,還能夠建索引,駭客淳將數據都緩存到內存,等等。 由於分區無需額外的數據結構記錄每一個分區有哪些數據--分區不須要精肯定位每條數據的位置,也就無需額外的數據結構--因此其代價很是低,只須要一個簡單的表達式就能夠表達每一個分區存放的是什麼數據。
爲了保證大數據量的可拓展性,通常有下面兩個策略:
上面咱們介紹的兩個分區策略都是基於兩個很是重要的假設:查詢可以過濾掉不少額外的分區,分區自己並不會帶來不少額外的代價。而事實證實,這兩個假設在某些場景下會有問題。
分區最大的有點是優化器能夠根據分區函數來過濾一些分區,根據粗粒度索引的優點,經過分區過濾一般能夠查詢掃描更少的數據。 對於分區表來講,很重要的一點是要在where條件中帶入分區列,有時候即便看似 多餘的也要帶上,這樣就可讓優化器可以過濾掉無需訪問的分區。若是沒有這些條件,mysql就須要讓對應的存儲引擎訪問這個表的全部分區,若是表很是大的話,就可能會很是慢。 mysql只能在使用分區函數的列自己進行比較時才能過濾分區,而不能根據表達式的值去過濾分區,即便這個表達式就是分區函數也不行。
mysql5.0版本以後開始引入視圖。視圖自己是一個虛擬表,不存聽任何數據,在使用sql語句訪問視圖的時候,它返回的數據是mysql從其餘表中生成的。 視圖和表是在同一個命名空間,mysql在不少地方對於視圖和表是一樣對待的。不過視圖和表也有不一樣,例如不能對視圖建立觸發器,也不能使用drop table命令刪除視圖。
mysql可使用兩種辦法處理視圖:合併算法和臨時表算法。若是可能儘量使用合併算法。
若是你想肯定mysql究竟是使用合併算法仍是臨時表算法,能夠explain一條針對視圖的簡單查詢:
explain select * from <view_name>
+----+-------------+------------+------------+--------+---------------+---------+---------+-------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+--------+---------------+---------+---------+-------------------+------+----------+-------------+
| 1 | PRIMARY | <derived2> | <null> | ALL | <null> | <null> | <null> | <null> | 34 | 100.0 | <null> |
| 2 | DERIVED | blog | <null> | index | user_id | user_id | 4 | <null> | 34 | 100.0 | Using index |
| 2 | DERIVED | u | <null> | eq_ref | PRIMARY | PRIMARY | 4 | test.blog.user_id | 1 | 100.0 | Using where |
+----+-------------+------------+------------+--------+---------------+---------+---------+-------------------+------+----------+-------------+
複製代碼
這裏的select_type爲derived,說明該視圖是採用的臨時表算法實現的。
可更新視圖是指能夠經過更新這個視圖來更新視圖涉及的相關表。只要指定了合適的條件,就能夠更新,刪除甚至向視圖中寫入數據。 若是視圖定義中包含了group by, union, 聚合函數,以及其餘一些特殊狀況,就不能被更新了。 更新視圖的查詢也能夠是一個關聯語句,可是有一個限制,被更新的列必須來自同一個表中,另外,全部使用臨時表算法實現的視圖都沒法被更新。
可使用視圖實現基於列的權限控制,卻不須要真正的在系統中建立列權限,所以沒有額外的開銷。
若是打算使用視圖來提高性能,須要作比較詳細的測試。即便合併算法實現的視圖也會有額外的開銷,並且視圖的性能很難預測。 在mysql優化器中,視圖的代碼執行路徑也徹底不一樣,這部分代碼測試還不透全面,可能會有一些音層缺陷和問題。因此咱們認爲視圖還不是那麼成熟。
mysql還不支持物化視圖(將視圖結果數據存放在一個能夠查看的表中,並按期從原始表中刷新數據到這個表中). mysql也不支持在視圖中建立索引。不過可使用構建緩存表或者彙總表的辦法來模擬物化視圖和索引。
mysql視圖實現上也有一些讓人煩惱的地方,例如,mysql並不會保存視圖定義的原始sql語句,因此打算經過執行 show create view 後在簡單的修改其結果的方式來從新定義視圖,可能會大失所望。show create view出來的視圖建立語句將以一種不友好的內部格式呈現,充滿了各類轉義符和引號,沒有代碼格式,沒有註釋,也沒有縮進。
使用外鍵是有成本的,好比外鍵一般都要求每次在修改數據時都要在另一張表中多執行一次查找操做。 雖然InnoDB強制外鍵使用索引,但仍是沒法消除這種約束檢查的開銷。若是外鍵列的選擇性很低,則會致使一個很是大且選擇性低的索引.
不過在某些場景下,外鍵會提高一些性能。若是想確保兩個相關表始終有一致的數據,那麼使用外鍵比在應用程序中檢查一致性的性能要高得多,此外,外鍵在相關數據的刪除和更新上,也比在應用中維護要更高效,不過外鍵維護操做是逐行進行的,因此這樣的更新會比批量刪除和更新要慢些。
外鍵約束使得查詢須要額外訪問一些別的表,這也意味着須要額外的鎖。若是向子表中插入一條記錄,外鍵約束會讓InnoDB檢查對應的父表記錄,也就須要對父表對應記錄進行加鎖操做,來確保這條記錄不會在這個事務完成之時就被刪除了。這回致使額外的鎖等待,甚至會致使一些死鎖。
若是隻是使用外鍵作約束,那一般在應用程序裏實現該約束會更好。外鍵會帶來很大的額外消耗。
mysql容許經過觸發器,存儲過程,函數的形式來存儲代碼,從mysql5.1開始,還能夠在定時任務中存放代碼,這個定時任務也被稱爲「事件」。存儲過程和存儲函數都被統稱爲「存儲程序」。
在mysql中使用存儲代碼的優勢:
存儲代碼也有以下缺點:
最後,存儲代碼是一種幫助應用隱藏複雜性,使得應用開發更簡單的方法。不過,它的性能可能更低,並且會給MySQL的複製等增長潛在的風險。因此當你打算使用存儲過程的時候,須要問問本身,到底但願程序邏輯在哪兒實現:是數據庫中仍是應用代碼中?這兩種作法均可以,也都很流行。只是當你編寫存儲代碼的時候,你須要明白這是將程序邏輯放在數據庫中。
當建立一個綁定變量sql時,客戶端向服務器發送了一個sql語句的原型。服務器收到這個sql語句框架後,解析並存儲這個sql語句的部分執行計劃,返回給客戶端一個sql語句處理句柄。之後每次執行這類查詢 ,客戶端都指定使用這個句柄。 綁定變量sql使用問號標記能夠接收參數的位置,當真正須要執行具體查詢的時候,則使用具體值代替這些問號。
綁定變量相對也更安全,無需在應用程序中處理轉義,一則更簡單了,二則也大大減小了sql注入和攻擊風險。
字符集是指一種從二進制編碼到某類字符符號的映射,校對是指一組用於某個字符集的排序規則。
每種字符集均可能有多種校對規則,而且都有一個默認的校對規則。
mysql查詢緩存保存查詢返回的完整結果,當查詢命中該緩存,mysql會當即返回結果,跳過了解析,優化和執行階段。
查詢緩存系統會跟蹤查詢中涉及的每一個表,若是這些表發生變化,那麼和這個表相關的全部的緩存數據都將失效。
查詢緩存對應用程序是徹底透明的。
mysql判斷存換命中的方法很簡單,緩存存放在一個引用表中,經過一個哈希值引用,這個哈希值包括了以下因素:查詢自己,當前要查詢的數據庫,客戶端協議的版本以及一些其餘可能影響返回結果的信息。 當判斷緩存是否命中時,mysql不會解析,正規化或者參數化查詢語句,而是直接使用sql語句和客戶端發送過來的其餘原始信息。任何字符上的不一樣,都會致使緩存的不命中。
查詢語句中有一些不肯定的數據時,則不會被緩存。若是查詢中包含任何用戶自定義函數,存儲函數,用戶變量,臨時表,mysql庫中的系統表,或者任何包含列級別權限的表,都不會被緩存。
查詢緩存對讀寫都會帶來額外的消耗:
若是查詢緩存使用了很大量的內存,緩存失效操做就可能稱爲一個很是嚴重的問題瓶頸。若是緩存中存放了大量的查詢結果,那麼緩存失效操做時整個系統均可能會僵死一下子。