HASH(id DIV 1000000)
,這將爲100萬數據創建一個分區。一方面實現了當初分區的目的,另外一方面比起使用時間範圍分區還避免了一個問題,就是當超過必定閾值時,若是使用時間範圍分區就必須新增分區。上一節介紹的兩個分區策略都基於兩個很重要的假設:查詢可以過濾掉不少額外的分區,分區自己並不會帶來不少額外的代價。node
可能會遇到問題的場景:mysql
NULL值會使分區過濾無效算法
分區的表達式的值能夠是NULL:第一個分區是一個特殊分區。sql
PARTITION BY RANGE YEAR(order_date)
分區,那麼全部order_date爲NULL或者是一個很是值的時候,記錄都會放到第一個分區。
WHERE order_date BETWEEN '2012-01-01' AND '2012-01-31'
,實際上MySQL會檢查兩個分區,由於YEAR()在接收非法值時會返回NULL而把記錄放到第一個分區。PARTITION p_nulls VALUES LESS THAN (0)
。這樣即便須要檢查第一個分區,代價也很是小PARTITION BY RANGE COLUMNS(order_date)
分區實現中的一些其餘限制:數據庫
訪問分區表,需在WHERE條件中帶入分區列,即便有時候看似多餘,這樣就可讓優化器過濾掉無須訪問的分區。編程
MySQL只能在使用分區函數的列的自己進行比較才能過濾分區,而不能根據表達式的值去過濾分區,即便這個表達式就是分區函數也不行。這和查詢中使用獨立的列才能使用索引的道理是同樣的。緩存
-- 沒法使用分區
mysql> EXPLAIN PARTITIONS SELECT * FROM sales_by_day WHERE YEAR(day) = 2010\G;
-- 可以使用分區
mysql> EXPLAIN PARTITIONS SELECT * FROM sales_by_day
-> WHERE day BETWEEN '2010-01-01' AND '2010-12-31'\G;複製代碼
優化器在處理查詢的過程當中老是儘量聰明地去過濾分區。例如,若分區表是關聯操做中的第二張表,且關聯條件是分區鍵,MySQL就只會在對應的分區裏匹配行。(EXPLAIN沒法顯示這種狀況下的分區過濾,由於這是運行時的分區過濾,而不是查詢優化階段的)安全
合併表是一種早期的、簡單的分區實現,和分區表相比有一些不一樣的限制,而且缺少優化。合併表容許用戶單獨訪問各個子表。分區表是將來的發展趨勢,合併表是一種將被淘汰的技術,在將來版本可能會被刪除,在這裏不作過多闡述。服務器
視圖自己是一個虛擬表,不存聽任何數據。在使用SQL語句訪問視圖的時候,它返回的數據是MySQL從其餘表生成的。網絡
工做原理:
-- 實現視圖最簡單的辦法是將SELECT語句的結果存放到臨時表中。
mysql> CREATE VIEW Oceania AS
-> SELECT * FROM Country WHERE Continent = 'Oceania'
-> WITH CHECK OPTION;
-- 當須要訪問視圖的時候,可直接訪問這個臨時表
mysql> SELECT Code, Name FROM Oceania WHERE Name = 'Australia';
-- MySQL使用的並算法:重寫含有視圖的查詢,將視圖的定義SQL直接包含進查詢的SQL中:
mysql> SELECT Code, Name FROM Country
-> WHERE Continent = 'Oceania' AND Name = 'Australia';
-- MySQL 使用的臨時表算法,如下SQL是爲展現用的。這樣作會有明顯的性能問題,優化器也很難優化在這個臨時表上的查詢。
mysql> CREATE TEMPORARY TABLE TMP_Oceania_123 AS
-> SELECT * FROM Country WHERE Continent = 'Oceania';
mysql> SELECT Code, Name FROM TMP_Oceania_123 WHERE Name = 'Australia';複製代碼
MySQL使用合併算法 和臨時表算法 來處理視圖。若是可能,儘量使用合併算法。
兩種算法的實現細節:
使用臨時表算法實現視圖的場景:
視圖的實現算法是視圖自己的屬性,和做用在視圖上的查詢語句無關。例如,能夠爲一個基於簡單查詢的視圖制定使用臨時表算法:CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM sakila.actor;
,這樣不管基於執行什麼樣的查詢,視圖都會生成一個臨時表。
CHECK OPTION
子句表示任何經過視圖更新的行,都必須符合視圖自己的WHERE條件定義。因此不能更新視圖之外的列MySQL還不支持物化視圖(指視圖結果數據存放在一個能夠查看的表中,並按期從原始表刷新數據到這個表),也不支持在視圖中建立索引。可使用構建緩存表或者彙總表的辦法來模擬物化視圖和索引
MySQL並不會保存視圖定義的原始SQL語句,因此不能經過執行SHOW CREATE VIEW後再簡單地修改其結果的方式來從新定義視圖。
若是打算修改視圖,而且無法找到視圖的原始的建立語句的話,能夠經過使用視圖.frm文件最後一行獲取一些信息。若是有FILE權限,甚至可直接使用LOAD_FILE()來讀取.frm中的視圖建立信息,在加上一些字符處理工做。
mysql> SELECT
-> REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
-> REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
-> SUBSTRING_INDEX(LOAD_FILE('/var/lib/mysql/world/Oceania.frm'),
-> '\nsource=', −1),
-> '\\_','\_'), '\\%','\%'), '\\\\','\\'), '\\Z','\Z'), '\\t','\t'),
-> '\\r','\r'), '\\n','\n'), '\\b','\b'), '\\\"','\"'), '\\\'','\''),
-> '\\0','\0')
-> AS source;複製代碼
在將來一段時間還不會用到,須要用到再看,感受更適合DBA,這裏只列舉經常使用的方式。
能夠在執行INSERT、UPDATE或者DELETE的時候,執行一些特定的操做。能夠在MySQL中指定是在SQL語句執行前觸發仍是在執行後觸發。
相似於LINUX的定時任務,不過徹底是在MySQL內部實現。
MySQL在服務器中提供只讀的、單向的遊標,並且只能在存儲過程或者更底層的客戶端API中使用。由於遊標中指向的對象都是存儲在臨時表中而不是實際查詢到的數據,因此MySQL遊標老是可讀的。
INSERT INTO tbl(col1, col2, col3) VALUES (?, ?, ?);
。綁定變量的SQL,使用問號標記能夠接收參數的位置,當真正須要執行具體查詢的時候,則使用具體值代替這些問號。理論上有些優化器只須要作一次,但實際上,下面的操做仍是都會被執行。根據優化器何時工做,能夠將優化分爲三類:
最主要的用途就是在存儲過程當中使用。
三種綁定變量類型的部分區別:
使用支持C語言調用約定的任何編程語言來實現用戶自定義函數(UDF)。UDF必須事先編譯後並動態連接到服務器上。
插件類型:
字符集是指一種從二進制編碼到某類字符符號的映射,能夠參考如何使用一個字節來表示英文字符。校對是指一組用於某個字符集的排序規則。
每種字符集均可能有多種校對規則,而且都有一個默認的校對規則,每一個校對規則都是針對某個特定的字符集,所以把字符集和校對規則統稱爲字符集。
MySQL有不少選擇用於控制字符集,這些選項和字符集很容易混淆。只有基於字符的值才真正的有字符集的概念。對於其餘類型的值,字符集只是一個設置,指定用哪一種字符集來作比較或者其餘操做。
MySQL的設置:
建立對象時的默認設置:
服務器和客戶端通訊時的設置:
服務器和客戶端通訊的時候,他們可能使用不一樣的字符集。這時,服務器端將進行必要的翻譯轉換工做:
根據須要,可使用SET NAMES或者SET CHARACTER語句來改變上面的設置。不過在服務器上使用這個命令只能改變服務器端的設置。客戶端程序和客戶端的API也須要使用正確的字符集才能避免在通訊時出現問題。
MySQL比較兩個字符串的大小時,經過將其轉換成同一個字符集再進行比較,若是兩個字符集不兼容的話,則會拋出錯誤。MySQL還會爲每一個字符串設置一個「可轉換性」,這個設置決定了值的字符集的優先級,於是會印象MySQL作字符集隱式轉換後的值。
還可使用前綴和COLLATE子句來指定字符串的字符集或者校對字符集。
mysql> SELECT _utf8 'hello world' COLLATE utf8_bin;複製代碼
一些特殊狀況:
可使用命令SHOW CHARACTERSET和SHOW COLLATION來查看MYSQL支持的字符集和校對規則。
極簡原則:最好先爲服務器或者數據庫選擇一個合理的字符集,而後根據不一樣的實際狀況,讓某些列選擇合適的字符集。
對於校對規則一般須要考慮的一個問題是,是否以大小寫敏感的方式比較字符串,或者是以字符串編碼的二進制值來比較大小。二進制校對規則直接使用字符的字節進行比較,而大小寫敏感的校對規則在多字節字符集時如德語有更復雜的比較規則。
MySQL如何選擇字符集和校對規則:
某些字符集和校對規則可能會須要更多的CPU操做、消耗更多的內存和存儲空間,甚至還會影響索引的正常使用。
計算每個文檔對象和查詢的相關度。相關度是基於匹配的關鍵詞個數,以及關鍵詞在文檔中出現的個數。在整個索引中出現次數越少的詞語,匹配的相關度就越高,相反很是常見的單詞就不會被搜索。
能夠在查詢中自定以某個被搜索詞語的相關性。布爾搜索經過停用詞列表過濾掉那些噪聲詞,另外還要求搜索的關鍵詞長度必須大於ft_min_word_len並小於ft_max_word_len。搜索返回的結果是未經排序的。
存儲引擎的事務特性能勾保證在存儲引擎級別實現ACID,而分佈式事務則讓存儲引擎級別的ACID擴展到數據庫層面,甚至擴展到多個數據庫之間,這須要兩個階段提交實現:
MySQL的緩存類型:
MySQL查詢緩存保存查詢返回的完整結果。當查詢命中該緩存,MySQL會馬上返回結果,跳過了解析、優化和執行階段。
隨着如今的通用服務器愈來愈大,查詢緩存被發現是一個影響服務器擴展性的因素。它可能成爲整個服務器的資源競爭單點,在多核服務器上還可能致使服務器僵死。建議默認關閉查詢緩存,若是查詢緩存做用很大的話,那就配置一個很小的查詢緩存空間(如幾十兆)。
緩存存放在一個引用表中,經過一個哈希值引用,這個哈希值包括了以下因素:即查詢自己、當前要查詢的數據庫、客戶端協議的版本等一些其餘可能會影響返回結果的信息。
當判斷緩存是否命中時,MySQL不會解析、「正規化」或者參數化查詢語句,而是直接使用SQL語句和客戶端發送過來的其餘原始信息。任何字符上的不一樣,例如空格、註釋,都會致使緩存不命中。
當查詢語句中有一些不肯定的數據時,則不會被緩存。例如包含函數NOW()或者CURRENT_DATE的查詢都不會被緩存。
-- 若是但願換成一個帶日期的查詢,那麼最好將其日期提早計算好,而不要直接使用函數
... DATE_SUB(CURRENT_DATE, INTERVAL 1 DAY) -- Not cacheable!
... DATE_SUB('2007-07-14’, INTERVAL 1 DAY) -- Cacheable複製代碼
子查詢和存儲過程都沒辦法使用查詢緩存,另外5.1版本以前,綁定變量也沒法使用。由於查詢緩存是在完整的SELECT語句基礎上的,並且只是在剛收到SQL語句的時候才檢查。
查詢緩存在不少時候能夠提高查詢性能,但自己是一個加鎖排他操做,另外打開查詢緩存對讀和寫都會帶來額外的消耗:
對InnoDB來講,事務的一些特性會限制查詢緩存的做用。當一個語句在事務中修改了某個表,MySQL會將這個表的對應的查詢緩存都設置失效,而事實上,InnoDB的多版本特性會暫時將這個修改對其它事務屏蔽。
若是查詢緩存使用了很大量的內存,緩存失效操做就可能會成爲一個很是嚴重的問題瓶頸。
查詢緩存是徹底存儲在內存中。
理想流程:
實際流程:
假設平均查詢結果很是小,服務器在併發地向不一樣的兩個鏈接返回結果,返回完結果後MySQL回收剩餘數據塊空間時會發現,回收的數據塊小於query_cache_min_res_unit,因此不可以直接在後續的內存塊分配中使用。考慮到這種狀況,數據塊的分配就更復雜些。
Qcache_lowmem_prunes
來查看有多少次失效是因爲內存不足致使的。配置:
減小碎片
提升查詢緩存的使用率
查詢緩存的工做原則是:執行查詢最快的方式就是不去執行。可是查詢仍然要發送到服務器端,服務器端還須要作一點點工做。所以能夠直接在客戶端進行緩存。