大話數據庫MySQL項目實戰的那幾個點

1、MySQL簡介

MySQL通常特製完整的MySQLRDBMS,是一個開源的關係型數據庫管理系統(Relational Database Management System),如今屬於Oracle公司。隨着MySQL功能的不斷完善,性能不斷提升,又有開源免費的優點,愈來愈多的企業選擇使用MySQL,而放棄商用收費的Oracle。php

2、MySQL結構

一、邏輯結構mysql

clipboard.png

MySQL採用的是客戶/服務器體系結構,所以實際使用時,有兩個程序:程序員

  1. 一個是MySQL服務器程序,指的是mysqlId程序,運行在數據庫服務器上,負責在網絡上監聽並處理來自客戶端的服務請求根據這些請求去訪問數據庫的內容,再把有關信息回傳給客戶;
  2. 另外一個程序是MySQL客戶端程序,負責鏈接到數據庫服務器,並經過發出命令來告知服務器它想要的操做。

從下面簡單的邏輯圖中能夠看出,MySQL內部大體分爲三層:sql

  1. 最上層是大部分基於網絡的C/S服務都有的部分,好比鏈接處理、受權認證、安全等;
  2. 第二層包括MySQL的不少核心服務功能,包括查詢解析、分析、優化、緩存以及全部的內置函數(例如,日期、時間、數學和加密函數),全部的跨存儲引擎的功能都在這一層實現:存儲過程、觸發器、視圖等。
  3. 第三層包含了存儲引擎,存儲引擎負責MySQL中歐數據的存儲和提取,是數據庫中很是重要很是核心的部分,也是MySQL區別與其餘數據庫的一個重要特性。

不一樣的存儲引擎有個字的特色,MySQL支持插入式的存儲引擎,能夠根據實際狀況選擇最合適的存儲引擎。不過目前對於絕大部分應用來講,MySQL默認的存儲引擎InnoDB應該就是其最佳選擇。我以爲剛開始學習的時候介紹不少不經常使用甚至不會用到的存儲引擎雖然可能會橫向比較,讓開發人員更瞭解每一個存儲引擎的特性,可是這樣對開發人員形成的困擾更大,還不如專心學習一種用途最普遍的存儲引擎,屏蔽其餘干擾,學到必定深度後再瞭解其餘存儲引擎的不一樣點。數據庫

二、體系結構緩存

clipboard.png

具體查看MySQL在物理上的體系結構,從上到下依次是:安全

  1. 鏈接池組件
  2. 管理服務和工具組件、SQL接口組件、查詢分析器組件、優化器組件、緩衝組件
  3. 插件式存儲引擎
  4. 物理文件

3、 數據庫和實例

區分兩個詞性能優化

clipboard.png

數據庫指物理上的存儲文件,實例是用來操做數據庫文件的。在MySQL數據庫中,實例與數據庫一般是一一對應的,這時兩個詞能夠互換,但在集羣狀況下,可能存在一個數據庫被對個數據實例使用的狀況.
MySQL是單進程多線程架構的數據庫,實例在系統上的表現就是一個進程。服務器

4、MySQL不得不說的八個陷阱

Mysql安裝簡單,速度較快,功能豐富。另外它仍是開源運動的標杆,它的偉大成就向咱們展現了一個成功的公司是能夠創建在開源代碼之上的。網絡

然而用過mysql的人都曾對着顯示器揮舞過拳頭。但你不可能發明一種每秒能保存成千上萬行互聯網數據,而且一點錯誤都沒有的技術吧。

如下列舉了8個開源關係型數據庫的缺陷,其中不只限於MySQL,還有是針對關係型數據庫的。只有明白了關係型數據庫和MySQL,才能更好地避免在使用MySQL中儘可能少地遇到一些意外。

一、根深蒂固的bugs

任何大的軟件包都有 bug。但稍微深刻了解一下,就會發現和 Mysql 相關的 bugs 自成體系。忽然你就須要留心,由於 NULL 並非以一樣的方式出現,外鍵約束也沒有像你想像的那樣執行,連主鍵自動增加也會出錯。

小問題大量存在,並且並不老是能夠修復,這就是爲何一些人保持一個列表。還好 MySQL 維護着一個很是好的 bug 報告系統,讓咱們能夠知道我些咱們沒法想像的事情,知道其餘人也在經受一樣的磨難。

二、關係表的不靈活性

關係表具備條理性,條理性是好的——可是,它使得程序員不得不編造或硬塞一些數據到已經定義好模式的列中。NoSQL開始愈來愈受到歡迎的緣由之一,就是它爲程序員提供了足夠的靈活性,來加速數據庫的使用。若是一個街道地址須要增長一行,那麼,你能夠將它很容易地插入到一個NoSQL文檔中。若是你想添加一個完整的新的數據塊,不管它包含什麼內容,文檔模型也能夠原封不動地接受你的數據,而沒必要改成它要求的數據格式。

試想一下,你用整數格式創建了一個所有是郵編的表格。這個表是十分高效的,它執行的規則也很好。忽然一次,有人上傳了一個使用了連字符的九位數郵編。或者還有可能,你獲得了一位來自加拿大客戶的信件,上面寫有郵政編碼。

這時,一切都亂了。老闆要求網站要在幾小時內恢復正常工做。然而,如今已經沒有時間來重建數據庫。程序員能夠作什麼?也許,能夠使用黑客手段把加拿大郵政編碼由base64的數字格式改成base 10格式?或者設置一個使用轉義編碼的輔助表格,用來講明真正的郵政編碼或者其餘?誰知道呢?處處都有黑客,他們都是危險的。但你沒有時間來搞定它。

MySQL的關聯規則讓每一個人都誠實和謹慎,但它能強制咱們避開易受攻擊和欺騙的麻煩。

三、存儲引擎混亂

整體來講,Mysql的存儲引擎接口定義還算良好的。MySQL不是實際上的同一的數據庫。它是由幾個數據庫組成,它們的大多數細節都被統一的表面掩蓋了。開始時有一個MyISAM引擎,它很快但在先後一致上不能作到完備。有時你須要速度而且能夠接受不一致的結果時是很好的。

當人們須要更多時,具有完整事務支持的Inno DB出現了。但這還不夠。如今,它可能有20種存儲引擎的選擇——這足以使一個數據庫管理員瘋狂。固然,有時在不一樣的存儲引擎之間切換而沒必要重寫你的SQL是很好的,可是切換後總會帶來混亂。這個表格我選擇的引擎是MyISAM仍是innoDB呢?或者,我決定輸出的數據是CSV格式的嗎?

四、JOIN聯合查詢

曾經,將數據分表保存是計算機科學史上的偉大創新。分開後的表不只結構簡單,使用上也簡化了許多。但它卻須要使用join語句來進行查詢。

sql經過一系列join構建的複雜查詢將開發者推入了困惑與絕望的深淵。並且存儲引擎也須要以最優的方式來高效地解析join語句。開發者須要絞盡腦汁編寫查詢語句,而後數據庫對其進行解析。

這就是不少注重運行速度的開發者放棄數據分錶轉而使用不規範數據表的緣由。不區分數據實體,將全部數據保存到一個大表中——以免複雜的查詢。這樣確實很快,而且服務器也不會耗盡內存。

如今的磁盤空間很廉價。8TB的磁盤已經在售,更大容量的也將上市。咱們再也不須要爲使用join而絞盡腦汁了。

五、分支的混亂

毋庸置疑,一個可靠的、獲得良好支持的MySQL分支,能夠帶來競爭和選擇,可是它也引發困惑和混亂。更糟糕的是,一個稱爲MariaDB的MySQL分支,由Monty Widenius維護着。他一樣也在參與編寫MySQL。那麼,Maria DB是真正獨立的值得咱們擁護的嗎?或者它是MySQL?咱們是否應該堅持使用由建立原始mysql數據庫的組織運營的核心代碼?或者咱們應該加入那些被認爲更聰明的,每每很酷的背叛者?

如何獲取關於兼容性的信息?雖然Maria DB和MySQL十分類似,但它們之間也有差別。這就是你們一直都在爭論它的緣由。在性能方面,在咱們查詢的範圍內,在兩個陣營中,也許它們的工做方式相同,但也許不一樣,也許未來會不一樣。

六、開發MySQL的動機

雖然MySQL是一款成功的開源產品,但它仍屬於商業中的一款產品,專業開發者須要靠它來得到利益,固然,最直接的利益就是薪資。當大多數用戶在持續地享受開源許可證帶來的最佳體驗時,毫無疑問這家公司還在爲賺取足夠的錢來維持運營而努力。這致使自由代碼在「社區版」和出售給企業的完整產品之間產生了奇怪的分岐。

咱們應該對這款產品付錢嗎?這種在社區版開展經營的行爲是否公平?企業版中額外的功能是否是一個噱頭,以引誘咱們不斷付費的呢?這至少說明一點,它是另外一些須要回答的問題:選用哪一個版本?遵守哪一種許可證?選用它的哪一個功能集?

七、原生JSON支持的缺少

經過安裝MySQL查看其年齡,而後你就知道須要添加哪些驅動程序使它變得可用。MySQL一般在3306端口上通訊,通常輸出的是它自己難以理解的格式化數據。若是要讓你的代碼和它通訊,你必須添加另外一層代碼,將MySQL的語言轉換成有用的東西。這些層的代碼,以庫的形式分發,常常須要人們購買一個商業許可證。

現代數據存儲層一般直接以JSON通訊。雖然MySQL和Maria DB如今有能力解析SQL中的JSON部分,但這還遠遠不夠,原生的JSON接口已經被普遍使用於CouchDB、MongoDB,或任何最新的工具中。

八、封閉源和專有模塊的興起

雖然MySQL是開源的,但除了一些在」開源核心「周邊開發的一些較新的、非開源的代碼和專有模塊。程序員也須要賺錢、須要生活,Oracle須要拿它的辛苦成果來換錢,這是一種現實,也是商業的性質。使用MySQL你也不能夠免費獲得任何東西。

要求MySQL始終堅持在一個很高的標準上,這有點不公平,由於開源的成功多是一個圈套。它開始能夠免費,但並不意味着它能夠始終免費。若是企業須要更多新的功能,他們就要經過各類方式付費來獲取。有時向Oracle付費,比本身來編寫代碼要便宜得多。有時商業的、不開源的代碼是有意義的。

MySQL雖然做爲一個成功的開源系統,但以上這些問題也總不可避免地出現,這就須要咱們在它們發生以前有個深入的認識,才能在從此的應用中避免沒必要要的麻煩。

在此我向你們推薦一個架構學習交流羣。交流學習羣號:575745314 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多

5、MySQL分佈式集羣搭建

1 準備集羣搭建環境

使用6臺虛擬機來搭建MYSQL集羣,相應的實驗環境與對應的MYSQL節點之間的對應關係以下圖所示:

clipboard.png

管理節點(MGM):這類節點的做用是管理MySQLCluster內的其餘節點,如提供配置數據,並中止節點,運行備份等。因爲這類節點負責管理其餘節點的配置,應該在啓動其餘節點以前啓動這類節點。MGM節點是用命令「ndb_mgmd」啓動的;

數據節點(NDB):這類節點用於保存Cluster的數據,數據節點的數目與副本的數目相關,是片斷的倍數。例如,對於兩個副本,每一個副本有兩個片斷,那麼就有4個數據節點,沒有必要設定過多的副本,在NDB中數據會盡可能的保存在內存中。數據節點使用命令「ndb」啓動的;

SQL節點:這是用來訪問Cluster數據的節點,對於MySQL Cluster,客戶端節點是使用NDB Cluster存儲引擎的傳統MySQL服務器。一般,SQL節點使用命令「mysqld-ndbcluster」啓動的;

二、準備安裝包

在官網上下載mysql的安裝包: mysql-cluster-gpl-7.4.11-Linux-glibc2.5-x86_64.tar.gz,並進行解壓。

三、集羣搭建流程

1]將上述安裝包解壓出來的文件都移到/usr/local/mysql下;

2]運行script目錄下的mysql-install-db.sh腳本,運行命令爲./mysql-install-db.sh --user=root--basedir =/usr/local/mysql --datadir=/usr/local/mysql;注意其中用戶爲root的名稱須要跟配置文件my.cnf中的相同;

在管理節點,數據節點,SQL節點上都執行上述安裝命令,從而完成對mysql的安裝;

四、集羣配置與啓動

1]在管理節點上須要完成對於集羣總體的配置配置:在/var/lib/mysql-cluster/config.ini中實現以下的配置信息:

clipboard.png

2]在數據節點中須要在my.cnf中完成對於數據節點的相關配置信息,以下:

clipboard.png

須要指明配置的數據節點的根目錄,數據目錄,socket鏈接配置,用戶配置,以及對應的管理節點的ip地址配置;將配置完成的配置文件移動到/etc/my.cnf,完成;

3]在SQL節點上完成對於SQL節點的配置信息,一樣的是在my.cnf中完成相應配置信息,並將配置文件移動到/etc/my.cnf中,相應的配置信息的設定以下所示:

clipboard.png

完成以上配置後,就能夠啓動集羣中的各個節點了。

五、集羣啓動

在啓動mysql集羣的時候,注意首先要啓動管理節點,並依次啓動其餘等若干個節點,相應的啓動步驟以下:

1]在管理節點上,切換到/usr/local/mysql/bin目錄下,執行ndb_mgmd -f /var/lib/mysql-cluster/config.ini命令,完成管理節點的啓動;

2]在各個數據節點上,切換到/usr/local/mysql/bin目錄下,執行ndbd --initial(第一次啓動時,不然執行ndbd便可),完成對數據節點的啓動;

3]在各個SQL節點上,一樣切換到/usr/local/mysql/bin目錄下,執行mysqld_safe --user=root完成啓動;

4]在管理節點上運行ndb_mgm命令,進入數據庫管理的客戶端,輸入show命令,查看與之相鏈接的各個節點的狀態;

5]在SQL節點上分別進入系統的安全狀態,並完成對root用戶的密碼修改,運行如下指令,進行密碼修改:

A use mysql,切換到mysql數據庫;

B UPDATE user SET Password = PASSWORD('123456')WHERE user = 'root';從而實現對root密碼的修改;

C flush privilege,完成修改;

6]修改使得任意主機都能連得上mysql,進行以下修改,一樣安裝第5步進入安全模式,並完成相應的修改,以下:

grant all on‘.’to ‘root@'%' identified by '123456';

這樣就能夠使得任意一個主機均可以經過root用戶來登陸mysql了;

六、集羣測試

在集羣上的一個SQL節點上執行建立數據庫,並建立一張表,並完成相應的數據插入,以下:

A create database ctest; //建立數據庫

B create table test(

id int primarykey; //建立一張表

);

C insert into test (id)values(1); //完成數據插入

登陸另一個SQL節點,並執行SQL查詢操做,看數據庫中是否已經有數據,以下:

select * from ctest;

若是有數據,表示數據插入成功;

七、關閉集羣

1]首先關閉管理節點和數據節點,須要在管理節點上執行命令,以下:./ndb_mgm -e shutdown;

2]而後關閉SQL節點,在SQL節點上執行命令/usr/local/mysql/support-fies/mysql.server stop(其中/usr/local/mysql/是mysql的安裝目錄).從而關閉SQL節點

在此我向你們推薦一個架構學習交流羣。交流學習羣號:575745314 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多

clipboard.png

6、MySQL 的最佳實踐

數據庫操做是當今 Web 應用程序中的主要瓶頸。 不只是 DBA(數據庫管理員)須要爲各類性能問題操心,程序員爲作出準確的結構化表,優化查詢性能和編寫更優代碼,也要費盡心思。 在本文中,我列出了一些針對程序員的 MySQL 優化技術。

在咱們開始學習以前,我補充一點:你能夠在 Envato Market 上找到大量的 MySQL 腳本和實用程序。

clipboard.png

1.優化查詢的查詢緩存

大部分MySQL服務器都有查詢緩存功能。這是提升性能的最有效的方法之一,這是由數據庫引擎私下處理的。當同一個查詢被屢次執行,結果會直接從緩存裏提取,這樣速度就很快。

主要的問題是,這對程序員來講太簡單了,不容易看到,咱們不少人都容易忽略。咱們其實是能夠組織查詢緩存執行任務的。

clipboard.png

查詢緩存在第一行不執行的緣由在於CURDTE()功能的使用。這適用於全部的非肯定性功能,就像NOW()和RAND()等等。。。由於功能返回的結果是可變的。MySQL決定禁用查詢器的查詢緩存。咱們所須要作的是經過添加一額外一行PHP,在查詢前阻止它發生。

2. EXPLAIN你的選擇查詢

使用EXPLAIN關鍵詞能夠幫助瞭解MySQL是怎樣運行你的查詢的。這有助於發現瓶頸和查詢或表結構的其它問題。

EXPLAIN的查詢結果會展現哪個索引被使用過,表示怎樣掃描和儲存的,等等。。。

選擇一個SELECT查詢(一個有鏈接的複雜查詢會更好),在它的前面添加關鍵詞EXPLAIN,這樣就能夠直接使用數據庫了。結果會以一個漂亮的表來展現。例如,就比如我執行鏈接時忘了添加一欄的索引:

clipboard.png

如今它只會從表2裏面掃描9和16行,而非掃描7883行。經驗法則是乘以全部「行」那一欄的數字,你的查詢性能會跟結果數字成比例的。

3. 獲取惟一行時使用LIMIT 1

有時當你查表時,你已經知道你正在查找的結果只有一行。你可能正在獲取惟一記錄,或者你可能只是查詢是否存在知足你的WHERE子句條件的記錄。

在這種狀況下,將LIMIT 1添加到查詢條件中能夠提升性能。這樣,數據庫引擎將在找到剛剛第一個記錄以後中止掃描記錄,而不是遍歷整個表或索引。

clipboard.png

4. 索引搜索字段

索引不只僅是爲了主鍵或惟一鍵。若是你會在你的表中按照任何列搜索,你就都應該索引它們。

clipboard.png

正如你所看到的,這個規則也適用於如 「last_name LIKE ‘a%’」的部分字符串搜索。當從字符串的開頭搜索時,MySQL就能夠使用那一列的索引。

你也應該明白什麼樣搜索能夠不使用有規律的索引。例如,當搜索一個單詞時(例如,」WHERE post_content LIKE ‘%apple%’」),你將不會看到普通索引的好處。你最好使用 mysql 全文搜索或者構建你本身的索引解決方案。

5. 索引並對鏈接使用一樣的字段類型

若是你的應用程序包含許多鏈接查詢, 你須要確保鏈接的字段在兩張表上都創建了索引。 這會影響MySQL如何內部優化鏈接操做。

此外,被鏈接的字段,須要使用一樣類型。例如, 若是你使用一個DECIMAL字段, 鏈接另外一張表的INT字段, MySQL將沒法使用至少一個索引。 即便字符編碼也須要使用相同的字符類型。

clipboard.png

6. 不要ORDER BY RAND()

起初這是一個聽起來挺酷的技巧, 讓許多菜鳥程序員陷入了這個陷阱。但你可能不知道,一旦你開始在查詢中使用它,你建立了很是可怕的查詢瓶頸。

若是你真的須要對結果隨機排序, 這有一個更好的方法。補充一些額外代碼,你將能夠防止當數據成指數級增加時形成的瓶頸。關鍵問題是,MySQL必須在排序以前對錶中的每一行執行RAND()操做(這須要處理能力),而且僅僅給出一行。

clipboard.png

因此挑選一個小於結果數的隨機數,並將其用做LIMIT子句中的偏移量。

7. 避免使用SELECT *

從數據表中讀取的數據越多,查詢操做速度就越慢。它增長了磁盤操做所需的時間。此外,當數據庫服務器與Web服務器分開時,因爲必須在服務器之間傳輸數據,將會有更長的網絡延遲。

這是一個好習慣:當你使用SELECT語句時老是指定你須要的列。

clipboard.png

8. 幾乎老是有一個id字段

在每一個以id列爲PRIMARY KEY的數據表中,優先選擇AUTO_INCREMENT或者INT。 也能夠優選使用UNSIGNED,由於該值不能爲負的。

即便你擁有一個具備惟一用戶名字段的用戶表,也不要將其做爲主鍵。 VARCHAR字段做爲主鍵(檢索)速度較慢。經過內部ID引用全部的用戶數據,你的代碼中將更加結構化。

有些後臺操做是由MySQL引擎自己完成的,它在內部使用主鍵字段。當數據庫設置越複雜(集羣,分區等…),這就變得更加劇要了。

這個規則的一個可能的例外是「關聯表」,用於兩個表之間的多對多類型的關聯。例如,「posts_tags」表中包含兩列:post_id,tag_id,用於保存表名爲「post」和「tags」的兩個表之間的關係。這些表能夠具備包含兩個id字段的PRIMARY鍵。

9. 相比VARCHAR優先使用ENUM

ENUM枚舉類型是很是快速和緊湊的。在內部它們像TINYINT同樣存儲,但它們能夠包含和顯示字符串值。這使他們成爲某些領域的完美候選。

若是有一個字段只包含幾種不一樣的值,請使用ENUM而不是VARCHAR。例如,它能夠是名爲「status」的列,而且只包含諸如「active」,「inactive」,「pending」,「expired」等的值…

關於如何重構你的數據表,甚至有一種方法是能夠從MySQL自己獲得「建議」。 當你有一個VARCHAR字段,它實際上建議你將該列類型更改成ENUM。這經過調用PROCEDURE ANALYZE()來完成。

在此我向你們推薦一個架構學習交流羣。交流學習羣號:575745314 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多

10. 使用PROCEDURE ANALYSE()獲取建議

PROCEDURE ANALYSE() 將使用MySQL分析列結構和表中的實際數據,爲你提供一些建議。它只有在數據表中有實際數據時纔有用,由於這在分析決策時很重要。

例如,若是你建立了一個INT類型的主鍵,但沒有太多行,MySQL則可能建議您改用MEDIUMINT。或者若是你使用VARCHAR字段,若是表裏只有不多的取值,你可能會獲得一個建議是將其轉換爲ENUM。

你也能夠在其中一個表視圖中單擊phpmyadmin中的「建議表結構」連接來執行此操做。

clipboard.png

請記住,這些只是建議。 若是你的數據表變得愈來愈大,他們甚至可能不是正確的建議。至於如何修改最終是你來決定。

11. 若是能夠的話使用NOT NULL

除非你有很是重要的理由使用NULL值,不然你應該設置你的列爲NOT NULL。

首先,問一下你本身在空字符串值和NULL值之間(對應INT字段:0 vs. NULL)是否有任何的不一樣.若是沒有理由一塊兒使用這兩個,那麼你就不須要一個NULL字段(你知道在Oracle中NULL和空字符串是同樣的嗎?)。

NULL列須要額外的空間,他們增長了你的比較語句的複雜度。若是能夠的話儘可能避免它們。固然,我理解一些人,他們也許有很是重要的理由使用NULL值,這不老是一件壞事。
摘自MySQL 文檔:

「行空列須要額外的空間來記錄它們的值是否爲空。 對於MyISAM表,每一個NULL列須要一點額外的,圍捕到最近的字節」。

12. 預處理語句

使用預處理語句有諸多好處,包括更高的性能和更好的安全性。

預處理語句默認狀況下會過濾綁定到它的變量,這對於避免SQL注入攻擊極爲有效。固然你也能夠指定要過濾的變量。但這些方法更容易出現人爲錯誤,也更容易被程序員遺忘。這在使用框架或 ORM 的時候會出現一些問題。

既然咱們關注性能,那就應該說說這個方面的好處。當在應用中屢次使用同一個查詢的時候,它的好處特別明顯。既然向同一個預備好的語句中傳入不一樣的參數值,MySQL 對這個語句也只會進行一次解析。

同時,最新版本的 MySQL 在傳輸預備好的語句時會採用二進制形式,這樣作的做用很是明顯,並且對減小網絡延遲頗有幫助。

曾經有一段時間,許多程序員爲了一個重要的緣由則避免使用預處理語句。這個緣由就是,它們不會被MySQL 緩存。不過在 5.1 版本的某個時候,查詢緩存也獲得的支持。

想在 PHP 中使用預處理語句,你能夠看看 mysqli 擴展 或使用數據抽象層,如 PDO。

clipboard.png

13. 無緩衝查詢

一般當你從腳本執行一個查詢,在它能夠繼續後面的任務以前將須要等待查詢執行完成。你能夠使用無緩衝的查詢來改變這一狀況。
在PHP 文檔中對 mysql_unbuffered_query() f函數有一個很好的解釋:

「mysql_unbuffered_query()發送SQL查詢查詢MySQL沒有自動抓取和緩衝結果行mysql_query()。
這節省了大量的內存生產大型結果集的SQL查詢,你能夠在結果集後當即開始工做第一行被檢索到的是你沒必要等到完整的SQL查詢已經完成。」

然而,它有必定的侷限性。你必須在執行另外一個查詢以前讀取全部的行或調用mysql_free_result() 。另外你不能在結果集上使用mysql_num_rows() 或 mysql_data_seek() 。

14. 使用 UNSIGNED INT 存儲IP地址

不少程序員沒有意識到能夠使用整數類型的字段來存儲 IP 地址,因此一直使用 VARCHAR(15) 類型的字段。使用 INT 只須要 4 個字節的空間,並且字段長度固定。

必須確保列是 UNSINGED INT 類型,由於 IP 地址可能會用到 32 位無符號整型數據的每個位。

在查詢中能夠使用 INET_ATON() 來把一個IP轉換爲整數,用 INET_NTOA() 來進行相反的操做。在 PHP 也有相似的函數,ip2long() 和 long2ip()。

clipboard.png

15. 固定長度(靜態)的表會更快

(譯者注:這裏提到的表的長度,實際是指表頭的長度,即表中每條數據佔用的空間大小,而不是指表的數據量)

若是表中全部列都是「固定長度」,那麼這個表被認爲是「靜態」或「固定長度」的。不固定的列類型包括 VARCHAR、TEXT、BLOB等。即便表中只包含一個這些類型的列,這個表就再也不是固定長度的,MySQL 引擎會以不一樣的方式來處理它。
固定長度的表會提升性能,由於 MySQL 引擎在記錄中檢索的時候速度會更快。若是想讀取表中的某一地,它能夠直接計算出這一行的位置。若是行的大小不固定,那就須要在主鍵中進行檢索。

它們也易於緩存,崩潰後容易重建。不過它們也會佔用更多空間。例如,若是你把一個 VARCHAR(20) 的字符改成 CHAR(20) 類型,它會老是佔用 20 個字節,無論裏面存的是什麼內容。

你能夠使用「垂直分區」技術,將長度變化的列拆分到另外一張表中。來看看:

16. 垂直分區

垂直分區是爲了優化表結構而對其進行縱向拆分的行爲。

示例 1: 你可能會有一張用戶表,包含家庭住址,而這個不是一個經常使用數據。這時候你能夠選擇把表拆分開,將住址信息保存到另外一個表中。這樣你的主用戶表就會更小。如你所知,表越小越快。

示例 2: 表中有一個 「last_login」 字段,用戶每次登陸網站都會更新這個字段,而每次更新都會致使這個表緩存的查詢數據被清空。這種狀況下你能夠將那個字段放到另外一張表裏,保持用戶表更新量最小。

不過你也須要確保不會常常聯合查詢分開後的兩張表,要否則你就得忍受由這帶來的性能降低。

17. 拆分大型DELETE或INSERT語句

若是你須要在網站上執行大型DELETE或INSERT查詢,則須要注意不要影響網絡流量。當執行大型語句時,它會鎖表並使你的Web應用程序中止。

Apache運行許多並行進程/線程。 所以它執行腳本效率很高。因此服務器不指望打開過多的鏈接和進程,這很消耗資源,特別是內存。

若是你鎖表很長時間(如30秒或更長),在一個高流量的網站,會致使進程和查詢堆積,處理這些進程和查詢可能須要很長時間,最終甚至使你的網站崩潰。

若是你的維護腳本須要刪除大量的行,只需使用LIMIT子句,以免阻塞。

clipboard.png

18.越少的列越快

對於數據庫引擎,磁盤多是最重要的瓶頸。更小更緊湊的數據、減小磁盤傳輸量,一般有助於性能提升。

MySQL文檔Storage Requirements 有全部數據類型清單。

若是已知表具備不多的行,則沒有理由是主鍵類型爲INT,能夠用MEDIUMINT、SMALLINT代替,甚至在某些狀況下使用TINYINT。 若是不須要完整時間記錄,請使用DATE而不是DATETIME。

確保留下合理的擴展空間,否則你可能會像Slashdot這樣。

19. 選擇正確的存儲引擎

MySQL有兩個主要存儲引擎,MyISAM和InnoDB。 每一個都有本身的優勢和缺點。

MyISAM適用於讀取繁重的應用程序,可是當有不少寫入時它不能很好地擴展。 即便你正在更新一行的一個字段,整個表也被鎖定,而且在語句執行完成以前,其餘進程甚至沒法讀取該字段。 MyISAM在計算SELECT COUNT(*)的查詢時很是快。

InnoDB是一個更復雜的存儲引擎,對於大多數小的應用程序,它比MyISAM慢。 但它支持基於行的鎖定,使其更好地擴展。 它還支持一些更高級的功能,好比事務。
● MyISAM存儲引擎
● InnoDB存儲引擎

20. 使用對象關係映射器(ORM, Object Relational Mapper)

經過使用ORM(對象關係映射器),你能夠得到必定的性能提高。ORM能夠完成的一切事情,手動編碼也可完成。但這可能意味着須要太多額外的工做,而且須要高水平的專業知識。

ORM以「延遲加載」著稱。這意味着它們僅在須要時獲取實際值。可是你須要當心處理他們,不然你可能最終建立了許多微型查詢,這會下降數據庫性能。

ORM還能夠將多個查詢批處理到事務中,其操做速度比向數據庫發送單個查詢快得多。

目前我最喜歡的PHP-ORM是Doctrine。我寫了一篇關於如何安裝Doctrine與CodeIgniter的文章(install Doctrine with CodeIgniter)。

21. 當心使用持久鏈接

持久鏈接意味着減小重建鏈接到MySQL的成本。 當持久鏈接被建立時,它將保持打開狀態直到腳本完成運行。 由於Apache重用它的子進程,下一次進程運行一個新的腳本時,它將重用相同的MySQL鏈接。

clipboard.png

理論上看起來不錯。 但從我我的(和許多其餘人)的經驗看來,這個功能可能會致使更多麻煩。 你可能會出現鏈接數限制問題、內存問題等等。

Apache老是並行運行的,它建立許多子進程。 這是持久鏈接在這種環境中不能很好工做的主要緣由。 在你考慮使用mysql_pconnect()以前,請諮詢你的系統管理員。

相關文章
相關標籤/搜索