教你編寫高性能的mysql語法 html
1、SQL語句查詢 java
在應用系統開發初期,因爲開發數據庫數據比較少,對於查詢SQL語句,複雜視圖的的編寫等體會不出SQL語句各類寫法的性能優劣,可是若是將應用系統提交 實際應用後,隨着數據庫中數據的增長,系統的響應速度就成爲目前系統須要解決的最主要的問題之一。系統優化中一個很重要的方面就是SQL語句的優化。對於 海量數據,劣質SQL語句和優質SQL語句之間的速度差異能夠達到上百倍,可見對於一個系統不是簡單地能實現其功能就可,而是要寫出高質量的SQL語句, 提升系統的可用性。 mysql
在多數狀況下,Oracle使用索引來更快地遍歷表,優化器主要根據定義的索引來提升性能。可是,若是在SQL語句的where子句中寫的SQL代 碼不合理,就會形成優化器刪去索引而使用全表掃描,通常就這種SQL語句就是所謂的劣質SQL語句。在編寫SQL語句時咱們應清楚優化器根據何種原則來刪 除索引,這有助於寫出高性能的SQL語句。 c++
2、SQL語句編寫注意問題
下面就某些SQL語句的where子句編寫中須要注意的問題做詳細介紹。在這些where子句中,即便某些列存在索引,可是因爲編寫了劣質的SQL,系統在運行該SQL語句時也不能使用該索引,而一樣使用全表掃描,這就形成了響應速度的極大下降。 sql
1. IS NULL 與 IS NOT NULL
不能用null做索引,任何包含null值的列都將不會被包含在索引中。即便索引有多列這樣的狀況下,只要這些列中有一列含有null,該列就會從索引中排除。也就是說若是某列存在空值,即便對該列建索引也不會提升性能。 數據庫
任何在where子句中使用is null或is not null的語句優化器是不容許使用索引的。 緩存
2. 聯接列 安全
對於有聯接的列,即便最後的聯接值爲一個靜態值,優化器是不會使用索引的。咱們一塊兒來看一個例子,假定有一個職工表(employee),對於一個 職工的姓和名分紅兩列存放(FIRST_NAME和LAST_NAME),如今要查詢一個叫比爾.克林頓(Bill Cliton)的職工。 性能優化
下面是一個採用聯接查詢的SQL語句, 服務器
select * from employss
where
first_name||''||last_name ='Beill Cliton'
上面這條語句徹底能夠查詢出是否有Bill Cliton這個員工,可是這裏須要注意,系統優化器對基於last_name建立的索引沒有使用。
當採用下面這種SQL語句的編寫,Oracle系統就能夠採用基於last_name建立的索引。
Select * from employee
where
first_name ='Beill' and last_name ='Cliton'
遇到下面這種狀況又如何處理呢?若是一個變量(name)中存放着Bill Cliton這個員工的姓名,對於這種狀況咱們又如何避免全程遍歷,使用索引呢?可使用一個函數,將變量name中的姓和名分開就能夠了,可是有一點需 要注意,這個函數是不能做用在索引列上。下面是SQL查詢腳本:
select * from employee
where
first_name = SUBSTR('&&name',1,INSTR('&&name',' ')-1)
and
last_name = SUBSTR('&&name',INSTR('&&name’,' ')+1)
3. 帶通配符(%)的like語句
一樣以上面的例子來看這種狀況。目前的需求是這樣的,要求在職工表中查詢名字中包含cliton的人。能夠採用以下的查詢SQL語句:
select * from employee where last_name like '%cliton%'
這裏因爲通配符(%)在搜尋詞首出現,因此Oracle系統不使用last_name的索引。在不少狀況下可能沒法避免這種狀況,可是必定要心中有 底,通配符如此使用會下降查詢速度。然而當通配符出如今字符串其餘位置時,優化器就能利用索引。在下面的查詢中索引獲得了使用:
select * from employee where last_name like 'c%'
4. Order by語句
ORDER BY語句決定了Oracle如何將返回的查詢結果排序。Order by語句對要排序的列沒有什麼特別的限制,也能夠將函數加入列中(象聯接或者附加等)。任何在Order by語句的非索引項或者有計算表達式都將下降查詢速度。
仔細檢查order by語句以找出非索引項或者表達式,它們會下降性能。解決這個問題的辦法就是重寫order by語句以使用索引,也能夠爲所使用的列創建另一個索引,同時應絕對避免在order by子句中使用表達式。
5. NOT
咱們在查詢時常常在where子句使用一些邏輯表達式,如大於、小於、等於以及不等於等等,也可使用and(與)、or(或)以及not(非)。NOT可用來對任何邏輯運算符號取反。下面是一個NOT子句的例子:
... where not (status ='VALID')
若是要使用NOT,則應在取反的短語前面加上括號,並在短語前面加上NOT運算符。NOT運算符包含在另一個邏輯運算符中,這就是不等於(<>)運算符。換句話說,即便不在查詢where子句中顯式地加入NOT詞,NOT仍在運算符中,見下例:
... where status <>'INVALID'
再看下面這個例子:
select * from employee where salary<>3000;
對這個查詢,能夠改寫爲不使用NOT:
select * from employee where salary<3000 or salary>3000;
雖然這兩種查詢的結果同樣,可是第二種查詢方案會比第一種查詢方案更快些。第二種查詢容許Oracle對salary列使用索引,而第一種查詢則不能使用索引。
6. IN和EXISTS
有時候會將一列和一系列值相比較。最簡單的辦法就是在where子句中使用子查詢。在where子句中可使用兩種格式的子查詢。
第一種格式是使用IN操做符:
... where column in(select * from ... where ...);
第二種格式是使用EXIST操做符:
... where exists (select 'X' from ...where ...);
我相信絕大多數人會使用第一種格式,由於它比較容易編寫,而實際上第二種格式要遠比第一種格式的效率高。在Oracle中能夠幾乎將全部的IN操做符子查詢改寫爲使用EXISTS的子查詢。
第二種格式中,子查詢以‘select 'X'開始。運用EXISTS子句無論子查詢從表中抽取什麼數據它只查看where子句。這樣優化器就沒必要遍歷整個表而僅根據索引就可完成工做(這裏假定 在where語句中使用的列存在索引)。相對於IN子句來講,EXISTS使用相連子查詢,構造起來要比IN子查詢困難一些。
經過使用EXIST,Oracle系統會首先檢查主查詢,而後運行子查詢直到它找到第一個匹配項,這就節省了時間。Oracle系統在執行IN子查 詢時,首先執行子查詢,並將得到的結果列表存放在在一個加了索引的臨時表中。在執行子查詢以前,系統先將主查詢掛起,待子查詢執行完畢,存放在臨時表中以 後再執行主查詢。這也就是使用EXISTS比使用IN一般查詢速度快的緣由。
同時應儘量使用NOT EXISTS來代替NOT IN,儘管兩者都使用了NOT(不能使用索引而下降速度),NOT EXISTS要比NOT IN查詢效率更高。
轉載聲明:本文轉自http://mysql.chinahtml.com/2006/mysql-mysql-11459227784273.shtml
=============================================================================
MySQL性能優化
1. 簡介
在 Web應用程序體系架構中,數據持久層(一般是一個關係數據庫)是關鍵的核心部分,它對系統的性能有很是重要的影響。MySQL是目前使用最多的開源數據 庫,可是MySQL數據庫的默認設置性能很是的差,僅僅是一個玩具數據庫。所以在產品中使用MySQL數據庫必須進行必要的優化。
優化是一個複雜的任務,本文描述MySQL相關的數據庫設計和查詢優化,服務器端優化,存儲引擎優化。
2. 數據庫設計和查詢優化
在MySQL Server性能調優中,首先要考慮的就是Database Schema設計,這一點是很是重要的。一個糟糕的Schema設計即便在性能調優的MySQL Server上運行,也會表現出不好的性能;和Schema類似,查詢語句的設計也會影響MySQL的性能,應該避免寫出低效的SQL查詢。這一節將詳細 討論這兩方面的優化。
2.1 Schema Design
Schema的優化取決於將要運行什麼樣的query,不一樣的query會有不一樣的Schema優化方案。2.2節將介紹Query Design的優化。Schema設計一樣受到預期數據集大小的影響。Schema設計時主要考慮:標準化,數據類型,索引。
2.1.1 標準化
標準化是在數據庫中組織數據的過程。其中包括,根據設計規則建立表並在這些表間創建關係;經過取消冗餘度與不一致相關性,該設計規則能夠同時保護數據並提 高數據的靈活性。一般數據庫標準化是讓數據庫設計符合某一級別的範式,一般知足第三範式便可。也有第四範式(也稱爲 Boyce Codd範式,BCNF))與第五範式存在,可是在實際設計中不多考慮。忽視這些規則可能使得數據庫的設計不太完美,但這不該影響功能。
標準化的特色:
1) 全部的「對象」都在它本身的table中,沒有冗餘。
2) 數據庫一般由E-R圖生成。
3) 簡潔,更新屬性一般只須要更新不多的記錄。
4) Join操做比較耗時。
5) Select,sort優化措施比較少。
6) 適用於OLTP應用。
非標準化的特色:
1) 在一張表中存儲不少數據,數據冗餘。
2) 更新數據開銷很大,更新一個屬性可能會更新不少表,不少記錄。
3) 在刪除數據是有可能丟失數據。
4) Select,order有不少優化的選擇。
5) 適用於DSS應用。
標準化和非標準化都有各自的優缺點,一般在一個數據庫設計中能夠混合使用,一部分表格標準化,一部分表格保留一些冗餘數據:
1) 對OLTP使用標準化,對DSS使用非標準化
2) 使用物化視圖。MySQL不直接支持該數據庫特性,可是能夠用MyISAM表代替。
3) 冗餘一些數據在表格中,例如將ref_id和name存在同一張表中。可是要注意更新問題。
4) 對於一些簡單的對象,直接使用value做爲建。例如IP address等
5) Reference by PRIMARY/UNIQUE KEY。MySQL能夠優化這種操做,例如:
java 代碼
- select city_name
- from city,state
- where state_id=state.id and state.code=‘CA’」 converted to 「select city_name from city where state_id=12
2.1.2 數據類型
最基本的優化之一就是使表在磁盤上佔據的空間儘量小。這能帶來性能很是大的提高,由於數據小,磁盤讀入較快,而且在查詢過程當中表內容被處理所佔用的內存更少。同時,在更小的列上建索引,索引也會佔用更少的資源。
可使用下面的技術可使表的性能更好而且使存儲空間最小:
1) 使用正確合適的類型,不要將數字存儲爲字符串。
2) 儘量地使用最有效(最小)的數據類型。MySQL有不少節省磁盤空間和內存的專業化類型。
3) 儘量使用較小的整數類型使表更小。例如,MEDIUMINT常常比INT好一些,由於MEDIUMINT列使用的空間要少25%。
4) 若是可能,聲明列爲NOT NULL。它使任何事情更快並且每列能夠節省一位。注意若是在應用程序中確實須要NULL,應該毫無疑問使用它,只是避免 默認地在全部列上有它。
5) 對於MyISAM表,若是沒有任何變長列(VARCHAR、TEXT或BLOB列),使用固定尺寸的記錄格式。這比較快可是不幸地可能會浪費一些空間。即 使你已經用CREATE選項讓VARCHAR列ROW_FORMAT=fixed,也能夠提示想使用固定長度的行。
6) 使用sample character set,例如latin1。儘可能少使用utf-8,由於utf-8佔用的空間是latin1的3倍。能夠在不須要使用utf-8的字段上面使用latin1,例如mail,url等。
2.1.3 索引
全部MySQL列類型能夠被索引。對相關列使用索引是提升SELECT操做性能的最佳途徑。使用索引應該注意如下幾點:
1) MySQL只會使用前綴,例如key(a, b) …where b=5 將使用不到索引。
2) 要選擇性的使用索引。在變化不多的列上使用索引並非很好,例如性別列。
3) 在Unique列上定義Unique index。
4) 避免創建使用不到的索引。
5) 在Btree index中(InnoDB使用Btree),能夠在須要排序的列上創建索引。
6) 避免重複的索引。
7) 避免在已有索引的前綴上創建索引。例如:若是存在index(a,b)則去掉index(a)。
8) 控制單個索引的長度。使用key(name(8))在數據的前面幾個字符創建索引。
9) 越是短的鍵值越好,最好使用integer。
10) 在查詢中要使用到索引(使用explain查看),能夠減小讀磁盤的次數,加速讀取數據。
11) 相近的鍵值比隨機好。Auto_increment就比uuid好。
12) Optimize table能夠壓縮和排序index,注意不要頻繁運行。
13) Analyze table能夠更新數據。
2.2 Designing queries
查詢語句的優化是一個Case by case的問題,不一樣的sql有不一樣的優化方案,在這裏我只列出一些通用的技巧。
1) 在有index的狀況下,儘可能保證查詢使用了正確的index。可使用EXPLAIN select …查看結果,分析查詢。
2) 查詢時使用匹配的類型。例如select * from a where id=5, 若是這裏id是字符類型,同時有index,這條查詢則使用不到index,會作全表掃描,速度會很慢。正確的應該是 … where id=」5」 ,加上引號代表類型是字符。
3) 使用--log-slow-queries –long-query-time=2查看查詢比較慢的語句。而後使用explain分析查詢,作出優化。
3. 服務器端優化
3.1 MySQL安裝
MySQL有不少發行版本,最好使用MySQL AB發佈的二進制版本。也能夠下載源代碼進行編譯安裝,可是編譯器和類庫的一些bug可能會使編譯完成的MySQL存在潛在的問題。
若是安裝MySQL的服務器使用的是Intel公司的處理器,可使用intel c++編譯的版本,在Linux World2005的一篇PPT中提到,使用intel C++編譯器編譯的MySQL查詢速度比正常版本快30%左右。Intel c++編譯版本能夠在MySQL官方網站下載。
3.2 服務器設置優化
MySQL默認的設置性能不好,因此要作一些參數的調整。這一節介紹一些通用的參數調整,不涉及具體的存儲引擎(主要指MyISAM,InnoDB,相關優化在4中介紹)。
--character-set:若是是單一語言使用簡單的character set例如latin1。儘可能少用Utf-8,utf-8佔用空間較多。
--memlock:鎖定MySQL只能運行在內存中,避免swapping,可是若是內存不夠時有可能出現錯誤。
--max_allowed_packet:要足夠大,以適應比較大的SQL查詢,對性能沒有太大影響,主要是避免出現packet錯誤。
--max_connections:server容許的最大鏈接。太大的話會出現out of memory。
--table_cache:MySQL在同一時間保持打開的table的數量。打開table開銷比較大。通常設置爲512。
--query_cache_size: 用於緩存查詢的內存大小。
--datadir:mysql存放數據的根目錄,和安裝文件分開在不一樣的磁盤能夠提升一點性能。
4. 存儲引擎優化
MySQL支持不一樣的存儲引擎,主要使用的有MyISAM和InnoDB。
4.1 MyISAM
MyISAM管理非事務表。它提供高速存儲和檢索,以及全文搜索能力。MyISAM在全部MySQL配置裏被支持,它是默認的存儲引擎,除非配置MySQL默認使用另一個引擎。
4.1.1 MyISAM特性
4.1.1.1 MyISAM Properties
1) 不支持事務,宕機會破壞表
2) 使用較小的內存和磁盤空間
3) 基於表的鎖,併發更新數據會出現嚴重性能問題
4) MySQL只緩存Index,數據由OS緩存
4.1.1.2 Typical MyISAM usages
1) 日誌系統
2) 只讀或者絕大部分是讀操做的應用
3) 全表掃描
4) 批量導入數據
5) 沒有事務的低併發讀/寫
4.1.2 MyISAM優化要點
1) 聲明列爲NOT NULL,能夠減小磁盤存儲。
2) 使用optimize table作碎片整理,回收空閒空間。注意僅僅在很是大的數據變化後運行。
3) Deleting/updating/adding大量數據的時候禁止使用index。使用ALTER TABLE t DISABLE KEYS。
4) 設置myisam_max_[extra]_sort_file_size足夠大,能夠顯著提升repair table的速度。
4.1.3 MyISAM Table Locks
1) 避免併發insert,update。
2) 可使用insert delayed,可是有可能丟失數據。
3) 優化查詢語句。
4) 水平分區。
5) 垂直分區。
6) 若是都不起做用,使用InnoDB。
4.1.4 MyISAM Key Cache
1) 設置key_buffer_size variable。MyISAN最主要的cache設置,用於緩存MyISAM表格的index數據,該參數只對MyISAM有影響。一般在只使用MyISAM的Server中設置25-33%的內存大小。
2) 可使用幾個不一樣的Key Caches(對一些hot data)。
a) SET GLOBAL test.key_buffer_size=512*1024;2) Preload index到Cache中能夠提升查詢速度。由於preloading index是順序的,因此很是快。
b) CACHE INDEX t1.i1, t2.i1, t3 IN test;
a) LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES;
4.2 InnoDB
InnoDB 給MySQL提供了具備提交,回滾和崩潰恢復能力的事務安全(ACID兼容)存儲引擎。InnoDB提供row level lock,而且也在SELECT語句提供一個Oracle風格一致的非鎖定讀。這些特點增長了多用戶部署和性能。沒有在InnoDB中擴大鎖定的須要,因 爲在InnoDB中row level lock適合很是小的空間。InnoDB也支持FOREIGN KEY約束。在SQL查詢中,你能夠自由地將InnoDB類型的表與其它MySQL的表的類型混合起來,甚至在同一個查詢中也能夠混合。
InnoDB是爲在處理巨大數據量時得到最大性能而設計的。它的CPU使用效率很是高。
InnoDB存儲引擎已經徹底與MySQL服務器整合,InnoDB存儲引擎爲在內存中緩存數據和索引而維持它本身的緩衝池。 InnoDB存儲它的表&索引在一個表空間中,表空間能夠包含數個文件(或原始磁盤分區)。這與MyISAM表不一樣,好比在MyISAM表中每一個表被存在 分離的文件中。InnoDB 表能夠是任何大小,即便在文件尺寸被限制爲2GB的操做系統上。
許多須要高性能的大型數據庫站點上使用了InnoDB引擎。著名的Internet新聞站點Slashdot.org運行在InnoDB上。 Mytrix, Inc.在InnoDB上存儲超過1TB的數據,還有一些其它站點在InnoDB上處理平均每秒800次插入/更新的負荷。
4.2.1 InnoDB特性
4.2.1.1 InnoDB Properties
1) 支持事務,ACID,外鍵。
2) Row level locks。
3) 支持不一樣的隔離級別。
4) 和MyISAM相比須要較多的內存和磁盤空間。
5) 沒有鍵壓縮。
6) 數據和索引都緩存在內存hash表中。
4.2.1.2 InnoDB Good For
1) 須要事務的應用。
2) 高併發的應用。
3) 自動恢復。
4) 較快速的基於主鍵的操做。
4.2.2 InnoDB優化要點
1) 儘可能使用short,integer的主鍵。
2) Load/Insert數據時按主鍵順序。若是數據沒有按主鍵排序,先排序而後再進行數據庫操做。
3) 在Load數據是爲設置SET UNIQUE_CHECKS=0,SET FOREIGN_KEY_CHECKS=0,能夠避免外鍵和惟一性約束檢查的開銷。
4) 使用prefix keys。由於InnoDB沒有key壓縮功能。
4.2.3 InnoDB服務器端設定
innodb_buffer_pool_size:這是InnoDB最重要的設置,對 InnoDB性能有決定性的影響。默認的設置只有8M,因此默認的數據庫設置下面InnoDB性能不好。在只有InnoDB存儲引擎的數據庫服務器上面, 能夠設置60-80%的內存。更精確一點,在內存容量容許的狀況下面設置比InnoDB tablespaces大10%的內存大小。
innodb_data_file_path:指定表數據和索引存儲的空間,能夠是一個或者多個文件。最後一個數據文件必須是自動擴充的,也只有最後一個 文件容許自動擴充。這樣,當空間用完後,自動擴充數據文件就會自動增加(以8MB爲單位)以容納額外的數據。例如: innodb_data_file_path=/disk1/ibdata1:900M;/disk2/ibdata2:50M:autoextend兩 個數據文件放在不一樣的磁盤上。數據首先放在ibdata1中,當達到900M之後,數據就放在ibdata2中。一旦達到50MB,ibdata2將以 8MB爲單位自動增加。若是磁盤滿了,須要在另外的磁盤上面增長一個數據文件。
innodb_autoextend_increment: 默認是8M, 若是一次insert數據量比較多的話, 能夠適當增長.
innodb_data_home_dir:放置表空間數據的目錄,默認在mysql的數據目錄,設置到和MySQL安裝文件不一樣的分區能夠提升性能。
innodb_log_file_size:該參數決定了recovery speed。太大的話recovery就會比較慢,過小了影響查詢性能,通常取256M能夠兼顧性能和recovery的速度
。
innodb_log_buffer_size:磁盤速度是很慢的,直接將log寫道磁盤會影響InnoDB的性能,該參數設定了log buffer的大小,通常4M。若是有大的blob操做,能夠適當增大。
innodb_flush_logs_at_trx_commit=2: 該參數設定了事務提交時內存中log信息的處理。
1) =1時,在每一個事務提交時,日誌緩衝被寫到日誌文件,對日誌文件作到磁盤操做的刷新。Truly ACID。速度慢。innodb_file_per_table:能夠存儲每一個InnoDB表和它的索引在它本身的文件中。
2) =2時,在每一個事務提交時,日誌緩衝被寫到文件,但不對日誌文件作到磁盤操做的刷新。只有操做系統崩潰或掉電纔會刪除最後一秒的事務,否則不會丟失事務。
3) =0時, 日誌緩衝每秒一次地被寫到日誌文件,而且對日誌文件作到磁盤操做的刷新。任何mysqld進程的崩潰會刪除崩潰前最後一秒的事務
transaction-isolation=READ-COMITTED: 若是應用程序能夠運行在READ-COMMITED隔離級別,作此設定會有必定的性能提高。
innodb_flush_method: 設置InnoDB同步IO的方式:
1) Default – 使用fsync()。innodb_thread_concurrency: InnoDB kernel最大的線程數。
2) O_SYNC 以sync模式打開文件,一般比較慢。
3) O_DIRECT,在Linux上使用Direct IO。能夠顯著提升速度,特別是在RAID系統上。避免額外的數據複製和double buffering(mysql buffering 和OS buffering)。
1) 最少設置爲(num_disks+num_cpus)*2。
2) 能夠經過設置成1000來禁止這個限制
5. 緩存
緩存有不少種,爲應用程序加上適當的緩存策略會顯著提升應用程序的性能。因爲應用緩存是一個比較大的話題,因此這一部分還須要進一步調研。
6. Reference
1) http://www.mysqlperformanceblog.com/
2) Advanced MySQL Performance Optimization, Peter Zaitsev, Tobias Asplund, MySQL Users Conference 2005
3) Improving MySQL Server Performance with Intel C++ Compiler,Peter Zaitsev,Linux World 2005
4) MySQL Performance Optimization, Peter Zaitsev, Percona Ltd, OPEN SOURCE DATABASE CONFERENCE 2006
5) MySQL Server Settings Tuning, Peter Zaitsev, co-founder, Percona Ltd, 2007
6) MySQL Reference Manual
轉載聲明:本文轉自http://www.javaeye.com/topic/144033