日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

mysql效率优化_MySQL性能优化的最佳12条经验

發(fā)布時間:2023/11/27 生活经验 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql效率优化_MySQL性能优化的最佳12条经验 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

數(shù)據(jù)庫的操作越來越成為整個應(yīng)用的性能瓶頸了,這點對于Web應(yīng)用尤其明顯。關(guān)于數(shù)據(jù)庫的性能,這并不只是DBA才需要擔心的事,而這更是我 們程序員需要去關(guān)注的事情。當我們?nèi)ピO(shè)計數(shù)據(jù)庫表結(jié)構(gòu),對操作數(shù)據(jù)庫時(尤其是查表時的SQL語句),

我們都需要注意數(shù)據(jù)操作的性能。這里,我們不會講過 多的SQL語句的優(yōu)化,而只是針對MySQL這一Web應(yīng)用最多的數(shù)據(jù)庫。希望下面的這些優(yōu)化技巧對你有用。

1. 為查詢緩存優(yōu)化你的查詢

大多數(shù)的MySQL服務(wù)器都開啟了查詢緩存。這是提高性最有效的方法之一,而且這是被MySQL的數(shù)據(jù)庫引擎處理的。當有很多相同的查詢被執(zhí)行了多次的時候,這些查詢結(jié)果會被放到一個緩存中,這樣,后續(xù)的相同的查詢就不用操作表而直接訪問緩存結(jié)果了。

這里最主要的問題是,對于程序員來說,這個事情是很容易被忽略的。因為,我們某些查詢語句會讓MySQL不使用緩存。請看下面的示例:

1 // 查詢緩存不開啟2 $r = mysql_query("SELECT username FROM user WHERE signup_date >= CURDATE()");

3

4 // 開啟查詢緩存5 $today = date("Y-m-d");

6 $r = mysql_query("SELECT username FROM user WHERE signup_date >= '$today'");

上面兩條SQL語句的差別就是 CURDATE() ,MySQL的查詢緩存對這個函數(shù)不起作用。所以,像 NOW() 和 RAND() 或是其它的諸如此類的SQL函數(shù)都不會開啟查詢緩存,因為這些函數(shù)的返回是會不定的易變的。

所以,你所需要的就是用一個變量來代替MySQL的函數(shù),從而 開啟緩存。

2. EXPLAIN 你的 SELECT 查詢

使用 EXPLAIN 關(guān)鍵字可以讓你知道MySQL是如何處理你的SQL語句的。這可以幫你分析你的查詢語句或是表結(jié)構(gòu)的性能瓶頸。

EXPLAIN 的查詢結(jié)果還會告訴你你的索引主鍵被如何利用的,你的數(shù)據(jù)表是如何被搜索和排序的……等等,等等。

挑一個你的SELECT語句(推薦挑選那個最復(fù)雜的,有多表聯(lián)接的),把關(guān)鍵字EXPLAIN加到前面。你可以使用phpmyadmin來做這個事。然后,你會看到一張表格。

3. 當只要一行數(shù)據(jù)時使用 LIMIT 1

當你查詢表的有些時候,你已經(jīng)知道結(jié)果只會有一條結(jié)果,但因為你可能需要去fetch游標,或是你也許會去檢查返回的記錄數(shù)。

在這種情況下,加上 LIMIT 1 可以增加性能。這樣一樣,MySQL數(shù)據(jù)庫引擎會在找到一條數(shù)據(jù)后停止搜索,而不是繼續(xù)往后查少下一條符合記錄的數(shù)據(jù)。

下面的示例,只是為了找一下是否有“中國”的用戶,很明顯,后面的會比前面的更有效率。(請注意,第一條中是Select *,第二條是Select 1)

1 // 沒有效率的: 2 $r = mysql_query("SELECT * FROM user WHERE country = 'China'");

3 if (mysql_num_rows($r) > 0) {

4 // ... 5 }

6

7 // 有效率的: 8 $r = mysql_query("SELECT 1 FROM user WHERE country = 'China' LIMIT 1");

9 if (mysql_num_rows($r) > 0) {

10 // ...11 }

4. 為搜索字段建索引

索引并不一定就是給主鍵或是唯一的字段。如果在你的表中,有某個字段你總要會經(jīng)常用來做搜索,那么,請為其建立索引吧。

另外,你應(yīng)該也需要知道什么樣的搜索是不能使用正常的索引的。例如,當你需要在一篇大的文章中搜索一個詞時,

如: “WHERE post_content LIKE ‘%apple%’”,索引可能是沒有意義的。你可能需要使用MySQL全文索引 或是自己做一個索引(比如說:搜索關(guān)鍵詞或是Tag什么的)

5. 在Join表的時候使用相當類型的例,并將其索引

如果你的應(yīng)用程序有很多 JOIN 查詢,你應(yīng)該確認兩個表中Join的字段是被建過索引的。這樣,MySQL內(nèi)部會啟動為你優(yōu)化Join的SQL語句的機制。

而且,這些被用來Join的字段,應(yīng)該是相同的類型的。例如:如果你要把 DECIMAL 字段和一個 INT 字段Join在一起,MySQL就無法使用它們的索引。對于那些STRING類型,還需要有相同的字符集才行。(兩個表的字符集有可能不一樣)

1 // 在state中查找company2 $r = mysql_query("SELECT company_name FROM users3 LEFT JOIN companies ON (users.state = companies.state)4 WHERE users.id =$user_id");

5

6 // 兩個 state 字段應(yīng)該是被建過索引的,而且應(yīng)該是相當?shù)念愋?#xff0c;相同的字符集。

6. 千萬不要 ORDER BY RAND()

想打亂返回的數(shù)據(jù)行?隨機挑一個數(shù)據(jù)?真不知道誰發(fā)明了這種用法,但很多新手很喜歡這樣用。但你確不了解這樣做有多么可怕的性能問題。

如果你真的想把返回的數(shù)據(jù)行打亂了,你有N種方法可以達到這個目的。這樣使用只讓你的數(shù)據(jù)庫的性能呈指數(shù)級的下降。

這里的問題是:MySQL會不得 不去執(zhí)行RAND()函數(shù)(很耗CPU時間),而且這是為了每一行記錄去記行,然后再對其排序。就算是你用了Limit 1也無濟于事(因為要排序)

下面的示例是隨機挑一條記錄

1 // 千萬不要這樣做:2 $r = mysql_query("SELECT username FROM user ORDER BY RAND() LIMIT 1");

3

4 // 這要會更好:5 $r = mysql_query("SELECT count(*) FROM user");

6 $d = mysql_fetch_row($r);

7 $rand = mt_rand(0,$d[0] - 1);

8

9 $r = mysql_query("SELECT username FROM user LIMIT$rand, 1");

7. 避免 SELECT *

從數(shù)據(jù)庫里讀出越多的數(shù)據(jù),那么查詢就會變得越慢。并且,如果你的數(shù)據(jù)庫服務(wù)器和WEB服務(wù)器是兩臺獨立的服務(wù)器的話,這還會增加網(wǎng)絡(luò)傳輸?shù)呢撦d。所以,你應(yīng)該養(yǎng)成一個需要什么就取什么的好的習(xí)慣。

// 不推薦$r = mysql_query("SELECT * FROM user WHERE user_id = 1");

$d = mysql_fetch_assoc($r);

echo "Welcome{$d['username']}";

// 推薦$r = mysql_query("SELECT username FROM user WHERE user_id = 1");

$d = mysql_fetch_assoc($r);

echo "Welcome{$d['username']}";

8. 永遠為每張表設(shè)置一個ID

我們應(yīng)該為數(shù)據(jù)庫里的每張表都設(shè)置一個ID做為其主鍵,而且最好的是一個INT型的(推薦使用UNSIGNED),并設(shè)置上自動增加的AUTO_INCREMENT標志。

就算是你 users 表有一個主鍵叫 “email”的字段,你也別讓它成為主鍵。使用 VARCHAR 類型來當主鍵會使用得性能下降。另外,在你的程序中,你應(yīng)該使用表的ID來構(gòu)造你的數(shù)據(jù)結(jié)構(gòu)。

而且,在MySQL數(shù)據(jù)引擎下,還有一些操作需要使用主鍵,在這些情況下,主鍵的性能和設(shè)置變得非常重要,比如,集群,分區(qū)……

在這里,只有一個情況是例外,那就是“關(guān)聯(lián)表”的“外鍵”,也就是說,這個表的主鍵,通過若干個別的表的主鍵構(gòu)成。我們把這個情況叫做“外鍵”。

比如:有一個“學(xué)生表”有學(xué)生的ID,有一個“課程表”有課程ID,那么,“成績表”就是“關(guān)聯(lián)表”了,其關(guān)聯(lián)了學(xué)生表和課程表,在成績表中,學(xué)生ID和課程ID叫“外鍵”其共同組成主鍵。

9. 使用 ENUM 而不是 VARCHAR

ENUM 類型是非??旌途o湊的。在實際上,其保存的是 TINYINT,但其外表上顯示為字符串。這樣一來,用這個字段來做一些選項列表變得相當?shù)耐昝馈?/p>

如果你有一個字段,比如“性別”,“國家”,“民族”,“狀態(tài)”或“部門”,你知道這些字段的取值是有限而且固定的,那么,你應(yīng)該使用 ENUM 而不是 VARCHAR。

MySQL也有一個“建議”(見第十條)告訴你怎么去重新組織你的表結(jié)構(gòu)。當你有一個 VARCHAR 字段時,這個建議會告訴你把其改成 ENUM 類型。使用 PROCEDURE ANALYSE() 你可以得到相關(guān)的建議。

10. 從 PROCEDURE ANALYSE() 取得建議

PROCEDURE ANALYSE() 會讓 MySQL 幫你去分析你的字段和其實際的數(shù)據(jù),并會給你一些有用的建議。只有表中有實際的數(shù)據(jù),這些建議才會變得有用,因為要做一些大的決定是需要有數(shù)據(jù)作為基礎(chǔ)的。

例如,如果你創(chuàng)建了一個 INT 字段作為你的主鍵,然而并沒有太多的數(shù)據(jù),那么,PROCEDURE ANALYSE()會建議你把這個字段的類型改成MEDIUMINT 。

或是你使用了一個 VARCHAR 字段,因為數(shù)據(jù)不多,你可能會得到一個讓你把它改成 ENUM 的建議。這些建議,都是可能因為數(shù)據(jù)不夠多,所以決策做得就不夠準。

一定要注意,這些只是建議,只有當你的表里的數(shù)據(jù)越來越多時,這些建議才會變得準確。一定要記住,你才是最終做決定的人。

11. 盡可能的使用 NOT NULL

除非你有一個很特別的原因去使用 NULL 值,你應(yīng)該總是讓你的字段保持 NOT NULL。這看起來好像有點爭議,請往下看。

首先,問問你自己“Empty”和“NULL”有多大的區(qū)別(如果是INT,那就是0和NULL)?如果你覺得它們之間沒有什么區(qū)別,那么你就不要使用NULL。(你知道嗎?在 Oracle 里,NULL 和 Empty 的字符串是一樣的!)

不要以為 NULL 不需要空間,其需要額外的空間,并且,在你進行比較的時候,你的程序會更復(fù)雜。 當然,這里并不是說你就不能使用NULL了,現(xiàn)實情況是很復(fù)雜的,依然會有些情況下,你需要使用NULL值。

下面摘自MySQL自己的文檔:

“NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”

12. Prepared Statements

Prepared Statements很像存儲過程,是一種運行在后臺的SQL語句集合,我們可以從使用 prepared statements 獲得很多好處,無論是性能問題還是安全問題。

Prepared Statements 可以檢查一些你綁定好的變量,這樣可以保護你的程序不會受到“SQL注入式”攻擊。當然,你也可以手動地檢查你的這些變量,然而,手動的檢查容易出問題,而且很經(jīng)常會被程序員忘了。

當我們使用一些framework或是ORM的時候,這樣的問題會好一些。

在性能方面,當一個相同的查詢被使用多次的時候,這會為你帶來可觀的性能優(yōu)勢。你可以給這些Prepared Statements定義一些參數(shù),而MySQL只會解析一次。

雖然最新版本的MySQL在傳輸Prepared Statements是使用二進制形勢,所以這會使得網(wǎng)絡(luò)傳輸非常有效率。

當然,也有一些情況下,我們需要避免使用Prepared Statements,因為其不支持查詢緩存。但據(jù)說版本5.1后支持了。

在PHP中要使用prepared statements,你可以查看其使用手冊:mysqli 擴展 或是使用數(shù)據(jù)庫抽象層,如: PDO.

1 // 創(chuàng)建 prepared statement 2 if ($stmt = $mysqli->prepare("SELECT username FROM user WHERE state=?")) {

3

4 // 綁定參數(shù) 5 $stmt->bind_param("s", $state);

6

7 // 執(zhí)行 8 $stmt->execute();

9

10 // 綁定結(jié)果11 $stmt->bind_result($username);

12

13 // 移動游標14 $stmt->fetch();

15

16 printf("%s is from %s\n", $username, $state);

17

18 $stmt->close();

19 }

以上內(nèi)容希望幫助到大家,需要更多文章可以關(guān)注公眾號:PHP從入門到精通,很多PHPer在進階的時候總會遇到一些問題和瓶頸,業(yè)務(wù)代碼寫多了沒有方向感,不知道該從那里入手去提升,對此我整理了一些PHP高級、架構(gòu)視頻資料和大廠PHP面試PDF免費獲取,

總結(jié)

以上是生活随笔為你收集整理的mysql效率优化_MySQL性能优化的最佳12条经验的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。