分頁優化+表鎖和庫存優化+數據庫的備份和導入

一.分頁優化技術

代碼參看: php/classic.phpjavascript

50331651記錄進行分頁,每頁顯示2條記錄,因而咱們用傳統php編碼方式,編寫分頁代碼以下:php

 

 

上傳到/var/www/html下進行測試,結果以下:html

若是訪問第1頁和第4頁,返回語句:java

 

 

 

使用explain執行計劃查詢比較靠前的頁數,發覺速度很快由於可使用上索引:mysql

 

 

 

若是訪問第4100000頁,返回語句:jquery

 

 

使用explain分析結果以下:linux

 

 

 

 

發覺這時若是分頁到了中間的頁數,這時咱們既須要排序又要分頁檢索數據的時候,就會出現Using filesort的選項,這選項的出現致使分頁在中間頁面的時候使用不上索引,所以出現全表掃描的過程,因此這個語句的查詢效率就大大的下降了,咱們在工做中若是遇到ALL的全表掃描咱們就必須優化這條語句,優化語句必須遵循一個理念:讓慢語句使用上索引,使得ALL消失,但功能不能發生改變,這時咱們應該如何優化,這時咱們能夠把分頁語句調整以下優化:算法

分頁傳統的公式以下: order by id asc + limit 偏移量,長度sql

分頁優化的公式以下: where id>偏移量 + order by id asc+ limit 長度數據庫

 

 

 

查詢第4100000頁獲得的結果以下:

 

 

通過優化後的算法,使用explain進行分析,能夠獲得以下結果:

 

 

發覺Using filesort被修改成Using Where所以分頁優化獲得提高,因此咱們未來在開發的過程當中若是須要分頁的數據達到千萬的級別時,咱們就須要使用如下優化分頁公式:

分頁優化的公式以下: where id>偏移量 + order by id asc + limit 長度

可是什麼還要知道當前的算法查詢的記錄是否準確:

 

 

 

 

.MyISAM的表鎖和庫存優化

 

在現實開發當中,電子商務網站會有一個搶購的活動,若是有一個id=4而且庫存量只有1的商品給用戶進行搶購,那麼這時有可能當全部的用戶同時進行搶購的時候就會發生一種叫作併發的行爲,這時會致使不少的用戶同時搶購一個商品成功,爲了防止這個狀況,確保只能有一我的搶購成功,咱們就須要使用Myisam中的表鎖,創建表結構和數據以下:

代碼參考: code/StoreGoods.sql

 

 

插入相關的測試數據以下:

 

因而咱們傳統編寫的搶購代碼以下所示:

代碼參考: code/goods.php

 

 

問題來了:若是這時發生了並不是的行爲,那麼其實有可能有大部分的用戶,能夠進入搶購的update代碼當中,那麼這時有可能發生多人搶購成功,而且庫存變爲負數的狀況,這時若是須要避免這個結果的產生,咱們須要加上表鎖,把代碼修改以下:

 

 

把代碼上傳到/var/www/html下,測試以下:

 

 

若是成功搶購,那麼繼續刷新就會提示如下結果:

 

 

 

.數據的列(字段)數據類型的正確選擇

1.數值數據類型

 

 

在表的創建中數值數據選取原則

人的年齡能夠選擇:

人通常很難超過139歲,若是你選擇int類型來存儲就是佔用4個字節,若是1000條記錄的大小就是4*1000=4000字節,若是你選擇tinyint就只有1個字節,1000條記錄只有1000字節的大小比原來int節約了4倍的存儲空間,所以人的年齡選擇tinyint

烏龜的年齡能夠選擇:

烏龜最短年齡也能夠超過500年,因此tinyint沒法存儲烏龜的年齡,所以咱們能夠選擇smallint來存儲,這時其實理論上能夠保存萬年神龜的年齡

主鍵能夠選擇:

假設是一個小學生的博客系統,那麼其實主鍵id選擇tinyint便可,由於小學生很難寫超過100篇文章,若是是技術人員的技術博客都屬於一些我的的筆記,因此咱們選擇smallint做爲主鍵的id就夠了,由於通常人很難寫超過2000篇文章,就算是金庸寫的博客也很難超過,假設你我的開發了一個商城網站,專賣手機產品,那麼應該選擇smallint,若是是一個間小公司的電子商務(中山壹加壹連鎖超市)能夠選擇MEDIUMINT,若是你開發是京東商城那麼請選擇int作主鍵

 

金錢能夠選擇:

若是遇到存儲貨幣或者金錢類型的字段,想都不用想使用DECIMAL(6,2)

2.時間和日期數據類型的大小

 

 

若是未來還須要用到時間的字段,建議直接使用timestamp,若是你使用int雖然也是4個字節,然而int存儲的是Unix時間戳,那麼就意味你有一個php代碼的轉化過程,很是的麻煩,而timestamp依然是4個字節但這個字段不須要你作任何的轉化,只須要使用一個mysql中的數據庫函數叫now()就能夠完成.

mysql的timestamp字段插入數據,會發覺存在2個問題:

代碼參考: code/timestamp.sql

 

 

 

 

 

這時以上的時間有可能不對的,由於在linux當中咱們安裝時候,安裝通常是系統時間,在linux修改時間須要同時修改系統時間和硬件時間,修改Linux的時間,須要使用如下兩個命令:

假設咱們須要把Linux的時間修改成2017-08-22 08:13:52秒

1)使用date命令

 

 

date在沒有任何的選項的時候,是用於查詢系統時間,發覺這個時間不是咱們想要的時間,所以咱們可使用date -s來進行時間的設置,-s是修改系統時間的選項

 

 

 

CST的意思是中國沿海時間的時區,通常在linux當中咱們使用中國時區都使用CST

2)使用clock --show命令顯示linux硬件時間

 

 

以上問題,能夠會在開發當中獲取的時間產生bug,所以咱們須要同步系統和硬件時間爲一致的時間,使用clock --systohc同步,--systohc就是把系統時間和硬件時間進行同步的選項:

執行命令,以下

 

 

這時再次對比系統時間和硬件時間以下:

 

 

若是咱們把字段的時間類型修改成timestamp也同時調整了Linux系統時間和硬件時間,那麼這時咱們若是使用php進行該字段的插入,那麼咱們在php中應該怎麼作呢?

代碼參考:php/news.php

 

 

上傳到/var/www/html下,測試效果以下:

 

 

上述代碼必須設置 時區,now()不要進行預處理

3.字符數據類型

 

 

若是你作博客或者新聞發佈信息的系統,標題字段選擇varchar,內容選擇text,這個進本上是一種常見的應用,BLOB的數據通常可能會產生一些亂碼的狀況因此建議不要使用在中文內容當中.

php開發咱們常常須要作時間字段的優化還有日誌記錄系統當中Ip字段的優化.

255.255.255.255 = 15字節(varhcar(15))

192.168.1.1 = 15字節(varchar(15)) = 15 * 1000 = 15000 字節

ip字段其實能夠優化成爲4個字節進行存儲,那麼就是4*1000=4000字節

因此若是使用varchar(15)或者char(15)來存儲ip的時候,你就有優化ip字段存儲的必要性了,若是但願把ip地址優化成爲4個字節的大小,咱們應該選擇int數據類型對ip進行存儲,可是若是把ip轉化成爲int呢,那麼這時咱們要學習兩個函數:

4.IP數據存儲

①爲ip字段選擇的數據類型(ip2long)

根據轉換的結果可使用如下在設計表時來選擇Ip字段的數據類型選擇Int

代碼詳細請參考:code/ip.sql

 

 

編寫php代碼以下:

代碼詳細請參考:php/ip2long.php

 

 

在默認狀況下,ip2long函數會把ip轉化成有簽名整型,所以咱們在php當中會獲取到負數的狀況,以下所示:

 

 

ip若是爲負數的轉化是屬於失敗的轉化,那咱們就須要把ip轉成無簽名整型獲取正整數

咱們就須要使用sprintf函數,函數描述以下:

 

 

編寫修改代碼以下:

 

 

上傳到/var/www/html下測試結果以下所示:

 

 

獲取了ip轉化無符號的結果,這時若是你但願直到當前的整數是否轉化成功,那麼就須要把整型轉化爲ip地址來進行驗證,使用long2ip

②long2ip函數(把整型轉換爲ip地址)

php代碼參看:php/long2ip.php(該代碼須要上傳到linux的/var/www/html下測試)

 

 

執行結果以下:

 

 

 

⑥ip優化的綜合實例,把ip爲192.168.84.88插入的數據表ipAddress當中,而且把插入的數在該表當中讀取出來,代碼以下所示:

php代碼參看:php/caseIp.php(該代碼須要上傳到linux的/var/www/html下測試)

1步:先完成pdo對ip地址轉化爲整型數據插入工做,代碼以下:

 

 

 

執行結果以下所示:

 

 

2步:把ip地址從數據庫讀取出來而且把整型轉化成爲ip地址,代碼以下:

 

 

執行結果以下所示:

 

 

.物理垂直分表和數據庫三範式

1.物理分表的概念

物理分表又稱爲手工分表,故名思議物理分表的工做是靠本身手動進行完成的,它的目的是把數據進行拆分管理.在物理分表中主要的分表思想有垂直分表和水平分表兩種,這種分表是一種數據庫的優化思想,因此須要引入數據庫範式的概念進行支持.

2.數據庫的三範式

在現實開發當中咱們通常是針對需求來知足需求,因而若是有如下需求咱們若是你看到眼前而不考慮長遠,咱們能夠把需求分析和設計作出如下決定,以下圖所示:

 

 

 

這樣的表設計天然可以知足需求1,然而它有利於長遠的發展嗎?若是你想知道是否適合長遠的發展最好就是繼續提出一個新的需求看看是否容易拓展或者直接知足,繼續提出需求以下:

 

 

要解決需求2若是你只看到眼前,那麼你可能會作出如下解決的,就是增長一個字段來添加歷史學科的成績:

 

 

這時又一個新的需求提出,這時問題就再次出現了,以下圖所示:

 

 

由於不斷字段去知足需求就會致使字段不斷增長,形成數據的冗餘,若是你但願解決以上這些問題的出現就須要使用物理垂直分表進行解決,然而垂直分表通常發生開發者開發項目和設計階段出現較多,因此與垂直分表相關的又一個叫作數據庫範式的理論進行支持,範式理論以下:

數據庫第1範式:把數據合理的進行拆分讓他們的共同點造成一個總體,而且造成後沒有繼續拆分必要 性,那麼就證實該總體一個合理的總體成爲符合數據庫第1範式(1NF),如上述問題,解決方案符合第1範式以下:

 

 

 

數據庫第2範式:因爲數據表又可能會存在相同而且重複的記錄可能,咱們須要解決整個問題就是加入主鍵,如上述問題,符合數據庫第2範式以下:

 

 

 

數據庫第3範式:因爲咱們把數據分別成爲了一個總體,那麼就須要把總體進行聯合,咱們把擁有主鍵的總體部分紅爲主表,把關聯主表的總體部分紅爲附屬表,那麼關聯他們的標識就是數據庫的第3方式的核心也就是外鍵,因此能夠認爲認爲數據庫第3範式的核心就是關聯性,如上述問題,符合第3範式設計以下:

 

 

數據庫三範式通常人也有把理解爲物理垂直分表的標準,只要符合數據庫三範式全部的規則,那麼都是垂直分表的過程而整個過程通常是咱們手動完成,所以物理垂直分表也稱爲手工垂直分表。

3.垂直分表的概念

分表時候,每一張表都是結構獨立的,表與表之間經過外鍵的形式把數據連接在一塊兒進行查詢。只要符合數據庫三範式的設計都屬於垂直分表的思想.

代碼詳細請參考:code/students.sql

1)業務需求

 

 

2)根據三範式設計表的結構

首先知足1NF和2NF,設計表結構以下:

 

 

然而知足3NF,設置關聯和外鍵,設計表結構以下:

 

 

3)爲表插入對應的數據

 

 

4)使用連表查詢得到數據

若是但願查找學號爲s123的人咱們就須要把學號字段進行主表和附屬表的關聯,原理以下:

 

 

編寫如下查詢語句連表查詢操做:

 

 

執行結果以下所示:

 

 

5)使用explain執行計劃查看索引使用狀況

 

 

執行結果發覺,垂直分表可使用到索引,由於符合數據庫3範式的設計就必定可以使用上索引。

 

4.數據庫的逆範式

逆範式化指的是經過增長冗餘或重複的數據來提升數據庫的讀性能.逆範式通俗的理解其實就是經過違反數據庫三範式的定義達到某種合理的設計的一種應用.其中水平分表就是一種逆範式的應用

五.物理水平分表實驗(37遊戲報團實驗)

在早期的網頁遊戲當中有一種叫組團攻城的活動,每個遊戲的玩家能夠在某一遊戲中進行報名組建其餘的玩家一塊兒玩遊戲,有時候可能不是隻有一個遊戲開展攻城的活動,而是多個遊戲開展攻城的活動,這時爲了更好地維護遊戲,這時咱們就可使用到水平分表,其原理圖以下所示:

 

 

咱們能夠把案例,按照以下步驟,部署到Linux當中

1步:把代碼經過ftp上傳/var/www/html

 

 

2步:創建一個名爲37games的數據以下:

 

 

3步:切換到/var/www/html下執行數據庫表的安裝,執行install_db.php文件

在執行腳本以前先確認數據庫連接的用戶名和密碼以及數據庫名稱,打開db.php文件,內容以下,能夠根據本身喜歡修改:

 

 

確認無誤後,就在/var/www/html下使用php命令執行install_db.php文件,以下圖所示:

 

 

查看數據庫37games當中發覺有2張表分別:tlcs_users和cycs_users

 

 

2張表的字段都是同樣的,只是表名不同

 

 

 

4步:在瀏覽中訪問linux中ip地址,出現如下界面,表明案例部署成功

 

 

 

5步:分析案例的目錄和文件以下:

js目錄 : 放置javascript庫文件的,jq.js是一個jquery框架

smarty目錄:用於放置smarty類庫的目錄

templates:是html模板的目錄

templates_c:是smarty編譯模板後的目錄

common.php : 一個數據庫連接,smarty實例化,遊戲產品列表數據引導的核心文件

count.php : 統計報團攻城的人數信息的文件

db.php : 數據庫的連接配置文件

games.php:遊戲產品的數組文件

index.php:網站報團首頁文件

install_db.php : linux安裝時執行的腳本文件

register.php: 報團插入數據庫的php文件

6步:分析首頁可知,頁面點機報團按鈕後,會把如下表單信息傳至register.php頁面

 

 

7步:在register.php代碼當中編寫以下代碼,獲取信息並插入數據庫當中

 

 

若是用戶報的屠龍傳說遊戲,那麼就會在tlcs_users當中添加數據:

 

 

若是用戶報的赤月傳說遊戲,那麼就會在cycs_users當中添加數據:

 

 

8步:實現水平分表的統計,咱們須要在count.php文件中編寫代碼以下:

 

 

測試結果以下:

 

 

這時問題來了,若是這時老闆提出一個新的需求,把一個叫作傳奇霸業的遊戲(mir)也進行攻城活動,那麼咱們就須要修改代碼以下:

9步:在games.php文件中加入對應遊戲代碼和遊戲名稱

 

 

在首頁就會顯示多一個遊戲

 

 

同時咱們還須要創建一張名爲mir_users的水平分表,來存儲傳奇霸業的用戶信息,使用命令以下:

 

 

 

 

10步:修改count.php的統計報表數據,代碼以下所示:

 

 

11步:修改smarty的模板文件templates/count.html,代碼以下:

 

 

測試以下:

 

 

 

物理水平分表自定義和拆分大數據的能力雖然很是的強,然而它有一個缺點就是因爲咱們形成數據的冗餘分佈,致使數據的統計變得麻煩,只能不一樣不斷修改代碼來知足需求,所以物理水平分表有優勢也有缺點,所以水平分表的物理優化咱們要付出必定的php邏輯編寫的時間代價,有沒有更好取代這種分表的,讓咱們的統計變得簡單的方法呢?在mysql5.1以後,其官方開發者提供了一種叫邏輯水平分表的手段

 

. MySql的邏輯水平分表

物理水平分表的好處在於自定義能力很強,但物理分表不利於數據的統計,所以MySql爲了解決物理水平分表的缺陷提出了邏輯水平分表的概念,邏輯水平分表是MySql自帶功能,它的好處就是分表的過程是系統自動完成的,而咱們寫的代碼不會像物理水平分表那樣疲於應對需求,邏輯水平分表主要有兩種。一種稱爲Range分表,一種稱爲List分表。

業界有些說法也叫Range分區和List分區。

1.使用Range形式的邏輯分表(切蛋糕)

RANGE分表其實比如生活中的切蛋糕中的概念,是基於範圍的數據切分RANGE主要是基於整數的分表。通常按主鍵進行範圍分表,假設當前主鍵的最大值爲5000,有時但願用一個範圍對數據進行拆分,好比把數據拆分爲5個等份:

1-1000:是5000的第1個範圍,把該範圍的數據做爲一張表

1001-2000:是5000的第2個範圍,把該範圍的數據做爲一張表

2001-3000:是5000的第3個範圍,把該範圍的數據做爲一張表

3001-4000:是5000的第3個範圍,把該範圍的數據做爲一張表

4001-5000:是5000的第4個範圍,把該範圍的數據做爲一張表

若是有以上的需求,那麼就可使用MySql的range分表技術,其原理圖以下:

 

 

若是把5000條記錄當作蛋糕,那麼拆分的數據就是把蛋糕切成了5等份

①建立表的時候指定range分表的範圍

代碼詳細請參考:code/range.sql

語法規則:

partition by range (字段)(

partition 分表名稱 values less than (範圍)

)

 

 

 

 

 

發覺系統自動幫咱們產生2個分表的區域

假設我但願有一張一些數據處於cake1000這張分表當中,那麼我應該如何插入?

分析可知:因爲這個分表是從id的範圍來分,若是id的範圍是1-999那麼就會處於cake1000當中,因此咱們插入數據以下:

 

 

執行結果以下:

 

 

發覺你插入數據其實能夠有效控制範圍

 

 

 

假設咱們插入的數據的id=2001,那麼會出現怎麼樣的狀況呢?

 

 

然而咱們的數據是分佈在不一樣的分表當中,若是咱們使用select count(*) from cakes能整成統計出記錄總數嗎?

這個答案是確定的,由於邏輯分表的功能和算法是開發者幫您實現的

 

 

假設咱們刪除了cake2000這個分表,那麼統計會改變嗎?也就是說數據會丟失嗎?

 

②刪除range分表

代碼詳細請參考:code/del_range.sql

語法規則:alter table 表名 drop partition 分表名稱;

若是咱們刪除cake2000這個分表,那麼咱們查詢id=1000是能夠查出來的

 

 

若是執行分表刪除,以下;

 

 

執行結果以下:

 

 

若是使用select count(*)進行統計查詢會發覺數據丟失了

注意:分表刪除數據會丟失

 

 

③添加range分表

代碼詳細請參考:code/add_range.sql

若是咱們添加一個數據超過了分表範圍,那麼就會報錯

 

 

 

語法規則:

alter table 表名 add partition (

    partition 分表名稱  values  less than (範圍)

)

 

 

執行的結果以下所示:

 

 

2.使用List形式的邏輯分表(分季度)

List分表其實簡單地理解爲把一年按季度的進行分表的應用便可,由於實際開發當中List分表主要用於年度季度報表的應用比較多,List分表也是按範圍的分表技術。假設當前要把1年的數據進行季度拆分,那麼1年能夠分爲4個季度:

3,4,5月分爲春季

6,7,8月分爲夏季

9,10,11月分爲秋季

12,1,2月份分爲冬季

這時range分表其實沒法達到這個功能,若是須要知足當前這個需求則能夠選擇List分表技術,其原理圖以下:

 

 

 

list分表通常用於財務報表的統計系統當中

①建立表的時候指定list分表的範圍

代碼詳細請參考:code/list.sql

語法規則:

partition by list (條件語句)(

partition 分表名稱  values  in (範圍)

)

 

 

執行結果以下:

 

 

②嘗試插入數據到夏季的分表當中

 

 

執行結果以下:

 

 

 

④刪除list分表

代碼詳細請參考:code/del_list.sql

語法規則:alter table 表名 drop partition 分表名稱;

 

 

執行結果會發覺,數據跟range同樣會丟失:

注意:分表刪除數據會丟失,list分表最好不要刪除分表,由於list的分表應用多數用於財務系統,財務系統的數據通常不建議刪除,因此最好不要刪除list分表種的分表

⑤添加list分表

代碼詳細請參考:code/add_list.sql

 

語法規則:

alter table 表名 add partition (

    partition 分表名稱  values  in (範圍)

)

 

 

執行結果以下:

 

 

 

list分表有1個特色,就是在mysql5.1.73版本,建議id字段設置爲普通索引,由於惟一性索引和主鍵在list分表當中不起做用,且沒法添加

 

 

 

 

 

這時咱們若是創建的是普通索引,那麼就不會出錯了

 

 

執行結果以下:

 

 

 

七.數據庫的備份和導入

①備份命令mysqldump

命令格式: mysqldump -uroot -p123456 [數據庫名稱] > 保存文件的路徑和名稱

 

 

/root/桌面就會存在37wan.sql這個文件,內容以下:

 

 

這時假設咱們刪除了37games這個數據庫,那麼就能夠利用備份的文件進行導入恢復

 

 

 

 

 

 

使用導入37wan.sql的方法進行數據庫恢復,步驟以下:

①創建37games的數據庫

 

 

退出mysql

②執行導入

 

 

 

 

相關文章
相關標籤/搜索