1、選取最適用的字段屬性
創新互聯網站建設公司一直秉承“誠信做人,踏實做事”的原則,不欺瞞客戶,是我們最起碼的底線! 以服務為基礎,以質量求生存,以技術求發展,成交一個客戶多一個朋友!專注中小微企業官網定制,做網站、成都做網站,塑造企業網絡形象打造互聯網企業效應。
MySQL 可以很好的支持大數據量的存取,但是一般說來,數據庫中的表越小,在它上面執行的查詢也就會越快。因此,在創建表的時候,為了獲得更好的性能,我們可以將表中字段的寬度設得盡可能小。例如,在定義郵政編碼這個字段時,如果將其設置為CHAR(255),顯然給數據庫增加了不必要的空間,甚至使用VARCHAR這種類型也是多余的,因為CHAR(6)就可以很好的完成任務了。同樣的,如果可以的話,我們應該使用MEDIUMINT而不是BIGIN來定義整型字段。
另外一個提高效率的方法是在可能的情況下,應該盡量把字段設置為NOT NULL,這樣在將來執行查詢的時候,數據庫不用去比較NULL值。
對于某些文本字段,例如“省份”或者“性別”,我們可以將它們定義為ENUM類型。因為在MySQL中,ENUM類型被當作數值型數據來處理,而數值型數據被處理起來的速度要比文本類型快得多。這樣,我們又可以提高數據庫的性能。
2、使用連接(JOIN)來代替子查詢(Sub-Queries)
MySQL 從4.1開始支持SQL的子查詢。這個技術可以使用SELECT語句來創建一個單列的查詢結果,然后把這個結果作為過濾條件用在另一個查詢中。例如,我們要將客戶基本信息表中沒有任何訂單的客戶刪除掉,就可以利用子查詢先從銷售信息表中將所有發出訂單的客戶ID取出來,然后將結果傳遞給主查詢,如下所示:
DELETE FROM customerinfo
WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )
使用子查詢可以一次性的完成很多邏輯上需要多個步驟才能完成的SQL操作,同時也可以避免事務或者表鎖死,并且寫起來也很容易。但是,有些情況下,子查詢可以被更有效率的連接(JOIN).. 替代。例如,假設我們要將所有沒有訂單記錄的用戶取出來,可以用下面這個查詢完成:
SELECT * FROM customerinfo
WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )
如果使用連接(JOIN).. 來完成這個查詢工作,速度將會快很多。尤其是當salesinfo表中對CustomerID建有索引的話,性能將會更好,查詢如下:
SELECT * FROM customerinfo
LEFT JOIN salesinfoON customerinfo.CustomerID=salesinfo.
CustomerID
WHERE salesinfo.CustomerID IS NULL
連接(JOIN).. 之所以更有效率一些,是因為 MySQL不需要在內存中創建臨時表來完成這個邏輯上的需要兩個步驟的查詢工作。
3、使用聯合(UNION)來代替手動創建的臨時表
MySQL 從 4.0 的版本開始支持 UNION 查詢,它可以把需要使用臨時表的兩條或更多的 SELECT 查詢合并的一個查詢中。在客戶端的查詢會話結束的時候,臨時表會被自動刪除,從而保證數據庫整齊、高效。使用 UNION 來創建查詢的時候,我們只需要用 UNION作為關鍵字把多個 SELECT 語句連接起來就可以了,要注意的是所有 SELECT 語句中的字段數目要想同。下面的例子就演示了一個使用 UNION的查詢。
SELECT Name, Phone FROM client
UNION
SELECT Name, BirthDate FROM author
UNION
SELECT Name, Supplier FROM product
4、事務
盡管我們可以使用子查詢(Sub-Queries)、連接(JOIN)和聯合(UNION)來創建各種各樣的查詢,但不是所有的數據庫操作都可以只用一條或少數幾條SQL語句就可以完成的。更多的時候是需要用到一系列的語句來完成某種工作。但是在這種情況下,當這個語句塊中的某一條語句運行出錯的時候,整個語句塊的操作就會變得不確定起來。設想一下,要把某個數據同時插入兩個相關聯的表中,可能會出現這樣的情況:第一個表中成功更新后,數據庫突然出現意外狀況,造成第二個表中的操作沒有完成,這樣,就會造成數據的不完整,甚至會破壞數據庫中的數據。要避免這種情況,就應該使用事務,它的作用是:要么語句塊中每條語句都操作成功,要么都失敗。換句話說,就是可以保持數據庫中數據的一致性和完整性。事物以BEGIN 關鍵字開始,COMMIT關鍵字結束。在這之間的一條SQL操作失敗,那么,ROLLBACK命令就可以把數據庫恢復到BEGIN開始之前的狀態。
BEGIN;
INSERT INTO salesinfo SET CustomerID=14;
UPDATE inventory SET Quantity=11
WHERE item='book';
COMMIT;
事務的另一個重要作用是當多個用戶同時使用相同的數據源時,它可以利用鎖定數據庫的方法來為用戶提供一種安全的訪問方式,這樣可以保證用戶的操作不被其它的用戶所干擾。
5、鎖定表
盡管事務是維護數據庫完整性的一個非常好的方法,但卻因為它的獨占性,有時會影響數據庫的性能,尤其是在很大的應用系統中。由于在事務執行的過程中,數據庫將會被鎖定,因此其它的用戶請求只能暫時等待直到該事務結束。如果一個數據庫系統只有少數幾個用戶
來使用,事務造成的影響不會成為一個太大的問題;但假設有成千上萬的用戶同時訪問一個數據庫系統,例如訪問一個電子商務網站,就會產生比較嚴重的響應延遲。
其實,有些情況下我們可以通過鎖定表的方法來獲得更好的性能。下面的例子就用鎖定表的方法來完成前面一個例子中事務的功能。
LOCK TABLE inventory WRITE
SELECT Quantity FROM inventory
WHEREItem='book';
...
UPDATE inventory SET Quantity=11
WHEREItem='book';
UNLOCK TABLES
這里,我們用一個 SELECT 語句取出初始數據,通過一些計算,用 UPDATE 語句將新值更新到表中。包含有 WRITE 關鍵字的 LOCK TABLE 語句可以保證在 UNLOCK TABLES 命令被執行之前,不會有其它的訪問來對 inventory 進行插入、更新或者刪除的操作。
6、使用外鍵
鎖定表的方法可以維護數據的完整性,但是它卻不能保證數據的關聯性。這個時候我們就可以使用外鍵。例如,外鍵可以保證每一條銷售記錄都指向某一個存在的客戶。在這里,外鍵可以把customerinfo 表中的CustomerID映射到salesinfo表中CustomerID,任何一條沒有合法CustomerID的記錄都不會被更新或插入到 salesinfo中。
CREATE TABLE customerinfo
(
CustomerID INT NOT NULL ,
PRIMARY KEY ( CustomerID )
) TYPE = INNODB;
CREATE TABLE salesinfo
(
SalesID INT NOT NULL,
CustomerID INT NOT NULL,
PRIMARY KEY(CustomerID, SalesID),
FOREIGN KEY (CustomerID) REFERENCES customerinfo
(CustomerID) ON DELETECASCADE
) TYPE = INNODB;
注意例子中的參數“ON DELETE CASCADE”。該參數保證當 customerinfo 表中的一條客戶記錄被刪除的時候,salesinfo 表中所有與該客戶相關的記錄也會被自動刪除。如果要在 MySQL 中使用外鍵,一定要記住在創建表的時候將表的類型定義為事務安全表 InnoDB類型。該類型不是 MySQL 表的默認類型。定義的方法是在 CREATE TABLE 語句中加上 TYPE=INNODB。如例中所示。
7、使用索引
索引是提高數據庫性能的常用方法,它可以令數據庫服務器以比沒有索引快得多的速度檢索特定的行,尤其是在查詢語句當中包含有MAX(), MIN()和ORDERBY這些命令的時候,性能提高更為明顯。那該對哪些字段建立索引呢?一般說來,索引應建立在那些將用于JOIN, WHERE判斷和ORDER BY排序的字段上。盡量不要對數據庫中某個含有大量重復的值的字段建立索引。對于一個ENUM類型的字段來說,出現大量重復值是很有可能的情況,例如 customerinfo中的“province”.. 字段,在這樣的字段上建立索引將不會有什么幫助;相反,還有可能降低數據庫的性能。我們在創建表的時候可以同時創建合適的索引,也可以使用ALTER TABLE或CREATE INDEX在以后創建索引。此外,MySQL
從版本3.23.23開始支持全文索引和搜索。全文索引在 MySQL 中是一個FULLTEXT類型索引,但僅能用于MyISAM 類型的表。對于一個大的數據庫,將數據裝載到一個沒有FULLTEXT索引的表中,然后再使用ALTER TABLE或CREATE INDEX創建索引,將是非??斓?。但如果將數據裝載到一個已經有FULLTEXT索引的表中,執行過程將會非常慢。
8、優化的查詢語句
絕大多數情況下,使用索引可以提高查詢的速度,但如果SQL語句使用不恰當的話,索引將無法發揮它應有的作用。下面是應該注意的幾個方面。首先,最好是在相同類型的字段間進行比較的操作。在MySQL 3.23版之前,這甚至是一個必須的條件。例如不能將一個建有索引的INT字段和BIGINT字段進行比較;但是作為特殊的情況,在CHAR類型的字段和 VARCHAR類型字段的字段大小相同的時候,可以將它們進行比較。其次,在建有索引的字段上盡量不要使用函數進行操作。
例如,在一個DATE類型的字段上使用YEAE()函數時,將會使索引不能發揮應有的作用。所以,下面的兩個查詢雖然返回的結果一樣,但后者要比前者快得多。
SELECT * FROM order WHERE YEAR(OrderDate)2001;
SELECT * FROM order WHERE OrderDate"2001-01-01";
同樣的情形也會發生在對數值型字段進行計算的時候:
SELECT * FROM inventory WHERE Amount/724;
SELECT * FROM inventory WHERE Amount24*7;
上面的兩個查詢也是返回相同的結果,但后面的查詢將比前面的一個快很多。第三,在搜索字符型字段時,我們有時會使用 LIKE 關鍵字和通配符,這種做法雖然簡單,但卻也是以犧牲系統性能為代價的。例如下面的查詢將會比較表中的每一條記錄。
SELECT * FROM books
WHERE name like "MySQL%"
但是如果換用下面的查詢,返回的結果一樣,但速度就要快上很多:
SELECT * FROM books
WHERE name="MySQL"and name"MySQM"
最后,應該注意避免在查詢中讓MySQL進行自動類型轉換,因為轉換過程也會使索引變得不起作用。
建議這種情況下,可以只查詢部分內容即可。可以用limit方法進行限制查詢條數的多少。
舉例:
select * from tablename;//此時查詢的是所有的記錄,用時可能比較多。
select * from tablename limit 20,40;//這樣就只會查詢出需要的第20條到40條。
備注:除了此優化外,可以只查詢需要的字段,還可以增加其余的一些where條件,來減少數據查詢的壓力。
一般進行性能分析,分如下三步:
首先需要使用慢查詢日志功能,去獲取所有查詢時間比較長的SQL語句
其次查看執行計劃查看有問題的SQL的執行計劃 explain
最后可以使用show profile查看有問題的SQL的性能使用情況
慢查詢日志分析
首先我們要使用慢查詢日志,因為它收集了查詢時間比較長的SQL語句,但使用之前必須開啟慢查詢日志,在配置文件my.cnf(一般為/etc/my.cnf)中的[mysqld] 增加如下參數:
slow_query_log=ONlong_query_time=3slow_query_log_file=/var/lib/mysql/slow-log.log復制代碼
增加這些參數之后,重啟MySQL,可以進行查詢慢查詢日志是否開啟。
1. 任何地方都不要使用 select * from t,用具體的字段列表代替“*“,不要返回用不到的任何字段。
2. 索引并不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
3. 并不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有字段sex,male、female幾乎各一半,那么即使在sex上建了索引也對查詢效率起不了作用。
4. 盡量使用數字型字段,若只含數值信息的字段盡量不要設計為字符型,這會降低查詢和連接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連接時會逐個比較字符串中每一個字符,而對于數字型而言只需要比較一次就夠了。
5. 盡可能的使用 varchar 代替 char ,因為首先變長字段存儲空間小,可以節省存儲空間, 其次對于查詢來說,在一個相對較小的字段內搜索效率顯然要高些。
6. 如果使用到了臨時表,在存儲過程的最后務必將所有的臨時表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統表的較長時間鎖定。
7. 對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where和order by相關的列上建立索引。
8. 應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描。
例如: select * from t where num is null
我們可以在num上設置默認值0,確保表中num列沒有null值,然后這樣查詢:select * from t where num=0。
1.當我們請求mysql服務器的時候,MySQL前端會有一個監聽,請求到了之后,服務器得到相關的SQL語句,執行之前(虛線部分為執行),還會做權限的判斷
2.通過權限之后,SQL就到MySQL內部,他會在查詢緩存中,看該SQL有沒有執行過,如果有查詢過,則把緩存結果返回,說明在MySQL內部,也有一個查詢緩存.但是這個查詢緩存,默認是不開啟的,這個查詢緩存,和我們的Hibernate,Mybatis的查詢緩存是一樣的,因為查詢緩存要求SQL和參數都要一樣,所以這個命中率是非常低的(沒什么卵用的意思)。
3.如果我們沒有開啟查詢緩存,或者緩存中沒有找到對應的結果,那么就到了解析器,解析器主要對SQL語法進行解析
4.解析結束后就變成一顆解析樹,這個解析樹其實在Hibernate里面也是有的,大家回憶一下,在以前做過Hibernate項目的時候,是不是有個一個antlr.jar。這個就是專門做語法解析的工具.因為在Hibernate里面有HQL,它就是通過這個工具轉換成SQL的,我們編程語言之所以有很多規范、語法,其實就是為了便于這個解析器解析,這個學過編譯原理的應該知道.
5.得到解析樹之后,不能馬上執行,這還需要對這棵樹進行預處理,也就是說,這棵樹,我沒有經過任何優化的樹,預處理器會這這棵樹進行一些預處理,比如常量放在什么地方,如果有計算的東西,把計算的結果算出來等等...
6.預處理完畢之后,此時得到一棵比較規范的樹,這棵樹就是要拿去馬上做執行的樹,比起之前的那棵樹,這棵得到了一些優化
7.查詢優化器,是MySQL里面最關鍵的東西,我們寫任何一條SQL,比如SELECT * FROM USER WHERE USERNAME = toby AND PASSWORD = 1,它會怎么去執行?它是先執行username = toby還是password = 1?每一條SQL的執行順序查詢優化器就是根據MySQL對數據統計表的一些信息,比如索引,比如表一共有多少數據,MySQL都是有緩存起來的,在真正執行SQL之前,他會根據自己的這些數據,進行一個綜合的判定,判斷這一次在多種執行方式里面,到底選哪一種執行方式,可能運行的最快.這一步是MySQL性能中,最關鍵的核心點,也是我們的優化原則.我們平時所講的優化SQL,其實說白了,就是想讓查詢優化器,按照我們的想法,幫我們選擇最優的執行方案,因為我們比MySQL更懂我們的數據.MySQL看數據,僅僅只是自己收集到的信息,這些信息可能是不準確的,MySQL根據這些信息選了一個它自認為最優的方案,但是這個方案可能和我們想象的不一樣.
8.這里的查詢執行計劃,也就是MySQL查詢中的執行計劃,比如要先執行username = toby還是password = 1
9.這個執行計劃會傳給查詢執行引擎,執行引擎選擇存儲引擎來執行這一份傳過來的計劃,到磁盤中的文件中去查詢,這個時候重點來了,影響這個查詢性能最根本的原因是什么?就是硬盤的機械運動,也就是我們平時熟悉的IO,所以一條查詢語句是快還是慢,就是根據這個時間的IO來確定的.那怎么執行IO又是什么來確定的?就是傳過來的這一份執行計劃.(優化就是制定一個我們認為最快的執行方案,最節省IO,和執行最快)
10.如果開了查詢緩存,則返回結果給客戶端,并且查詢緩存也放一份。
數據庫優化一方面是找出系統的瓶頸,提高MySQL數據庫的整體性能,而另一方面需要合理的結構設計和參數調整,以提高用戶的相應速度,同時還要盡可能的節約系統資源,以便讓系統提供更大的負荷.
1. 優化一覽圖
2. 優化
筆者將優化分為了兩大類,軟優化和硬優化,軟優化一般是操作數據庫即可,而硬優化則是操作服務器硬件及參數設置.
2.1 軟優化
2.1.1 查詢語句優化
1.首先我們可以用EXPLAIN或DESCRIBE(簡寫:DESC)命令分析一條查詢語句的執行信息.
2.例:
顯示:
其中會顯示索引和查詢數據讀取數據條數等信息.
2.1.2 優化子查詢
在MySQL中,盡量使用JOIN來代替子查詢.因為子查詢需要嵌套查詢,嵌套查詢時會建立一張臨時表,臨時表的建立和刪除都會有較大的系統開銷,而連接查詢不會創建臨時表,因此效率比嵌套子查詢高.
2.1.3 使用索引
索引是提高數據庫查詢速度最重要的方法之一,關于索引可以參高筆者MySQL數據庫索引一文,介紹比較詳細,此處記錄使用索引的三大注意事項:
2.1.4 分解表
對于字段較多的表,如果某些字段使用頻率較低,此時應當,將其分離出來從而形成新的表,
2.1.5 中間表
對于將大量連接查詢的表可以創建中間表,從而減少在查詢時造成的連接耗時.
2.1.6 增加冗余字段
類似于創建中間表,增加冗余也是為了減少連接查詢.
2.1.7 分析表,,檢查表,優化表
分析表主要是分析表中關鍵字的分布,檢查表主要是檢查表中是否存在錯誤,優化表主要是消除刪除或更新造成的表空間浪費.
1. 分析表: 使用 ANALYZE 關鍵字,如ANALYZE TABLE user;
2. 檢查表: 使用 CHECK關鍵字,如CHECK TABLE user [option]
option 只對MyISAM有效,共五個參數值:
3. 優化表:使用OPTIMIZE關鍵字,如OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE user;
LOCAL|NO_WRITE_TO_BINLOG都是表示不寫入日志.,優化表只對VARCHAR,BLOB和TEXT有效,通過OPTIMIZE TABLE語句可以消除文件碎片,在執行過程中會加上只讀鎖.
2.2 硬優化
2.2.1 硬件三件套
1.配置多核心和頻率高的cpu,多核心可以執行多個線程.
2.配置大內存,提高內存,即可提高緩存區容量,因此能減少磁盤I/O時間,從而提高響應速度.
3.配置高速磁盤或合理分布磁盤:高速磁盤提高I/O,分布磁盤能提高并行操作的能力.
2.2.2 優化數據庫參數
優化數據庫參數可以提高資源利用率,從而提高MySQL服務器性能.MySQL服務的配置參數都在my.cnf或my.ini,下面列出性能影響較大的幾個參數.
2.2.3 分庫分表
因為數據庫壓力過大,首先一個問題就是高峰期系統性能可能會降低,因為數據庫負載過高對性能會有影響。另外一個,壓力過大把你的數據庫給搞掛了怎么辦?所以此時你必須得對系統做分庫分表 + 讀寫分離,也就是把一個庫拆分為多個庫,部署在多個數據庫服務上,這時作為主庫承載寫入請求。然后每個主庫都掛載至少一個從庫,由從庫來承載讀請求。
2.2.4 緩存集群
如果用戶量越來越大,此時你可以不停的加機器,比如說系統層面不停加機器,就可以承載更高的并發請求。然后數據庫層面如果寫入并發越來越高,就擴容加數據庫服務器,通過分庫分表是可以支持擴容機器的,如果數據庫層面的讀并發越來越高,就擴容加更多的從庫。但是這里有一個很大的問題:數據庫其實本身不是用來承載高并發請求的,所以通常來說,數據庫單機每秒承載的并發就在幾千的數量級,而且數據庫使用的機器都是比較高配置,比較昂貴的機器,成本很高。如果你就是簡單的不停的加機器,其實是不對的。所以在高并發架構里通常都有緩存這個環節,緩存系統的設計就是為了承載高并發而生。所以單機承載的并發量都在每秒幾萬,甚至每秒數十萬,對高并發的承載能力比數據庫系統要高出一到兩個數量級。所以你完全可以根據系統的業務特性,對那種寫少讀多的請求,引入緩存集群。具體來說,就是在寫數據庫的時候同時寫一份數據到緩存集群里,然后用緩存集群來承載大部分的讀請求。這樣的話,通過緩存集群,就可以用更少的機器資源承載更高的并發。
一個完整而復雜的高并發系統架構中,一定會包含:各種復雜的自研基礎架構系統。各種精妙的架構設計.因此一篇小文頂多具有拋磚引玉的效果,但是數據庫優化的思想差不多就這些了.
標題名稱:mysql怎么優化延時間,mysql慢優化
文章路徑:http://m.kartarina.com/article32/hegdsc.html
成都網站建設公司_創新互聯,為您提供App開發、電子商務、Google、用戶體驗、網站建設、動態網站
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯