mysql海量資料庫優化(資料庫海量數據優化)

本文目錄一覽:

優化MYSQL資料庫的方法

在開始演示之前,我們先介紹下兩個概念。

概念一,數據的可選擇性基數,也就是常說的cardinality值。

查詢優化器在生成各種執行計劃之前,得先從統計信息中取得相關數據,這樣才能估算每步操作所涉及到的記錄數,而這個相關數據就是cardinality。簡單來說,就是每個值在每個欄位中的唯一值分布狀態。

比如表t1有100行記錄,其中一列為f1。f1中唯一值的個數可以是100個,也可以是1個,當然也可以是1到100之間的任何一個數字。這裡唯一值越的多少,就是這個列的可選擇基數。

那看到這裡我們就明白了,為什麼要在基數高的欄位上建立索引,而基數低的的欄位建立索引反而沒有全表掃描來的快。當然這個只是一方面,至於更深入的探討就不在我這篇探討的範圍了。

概念二,關於HINT的使用。

這裡我來說下HINT是什麼,在什麼時候用。

HINT簡單來說就是在某些特定的場景下人工協助MySQL優化器的工作,使她生成最優的執行計劃。一般來說,優化器的執行計劃都是最優化的,不過在某些特定場景下,執行計劃可能不是最優化。

比如:表t1經過大量的頻繁更新操作,(UPDATE,DELETE,INSERT),cardinality已經很不準確了,這時候剛好執行了一條SQL,那麼有可能這條SQL的執行計劃就不是最優的。為什麼說有可能呢?

來看下具體演示

譬如,以下兩條SQL,

A:

select * from t1 where f1 = 20;

B:

select * from t1 where f1 = 30;

如果f1的值剛好頻繁更新的值為30,並且沒有達到MySQL自動更新cardinality值的臨界值或者說用戶設置了手動更新又或者用戶減少了sample page等等,那麼對這兩條語句來說,可能不準確的就是B了。

這裡順帶說下,MySQL提供了自動更新和手動更新表cardinality值的方法,因篇幅有限,需要的可以查閱手冊。

那回到正題上,MySQL 8.0 帶來了幾個HINT,我今天就舉個index_merge的例子。

示例表結構:

mysql desc t1;+————+————–+——+—–+———+—————-+| Field      | Type         | Null | Key | Default | Extra          |+————+————–+——+—–+———+—————-+| id         | int(11)      | NO   | PRI | NULL    | auto_increment || rank1      | int(11)      | YES  | MUL | NULL    |                || rank2      | int(11)      | YES  | MUL | NULL    |                || log_time   | datetime     | YES  | MUL | NULL    |                || prefix_uid | varchar(100) | YES  |     | NULL    |                || desc1      | text         | YES  |     | NULL    |                || rank3      | int(11)      | YES  | MUL | NULL    |                |+————+————–+——+—–+———+—————-+7 rows in set (0.00 sec)

表記錄數:

mysql select count(*) from t1;+———-+| count(*) |+———-+|    32768 |+———-+1 row in set (0.01 sec)

這裡我們兩條經典的SQL:

SQL C:

select * from t1 where rank1 = 1 or rank2 = 2 or rank3 = 2;

SQL D:

select * from t1 where rank1 =100  and rank2 =100  and rank3 =100;

表t1實際上在rank1,rank2,rank3三列上分別有一個二級索引。

那我們來看SQL C的查詢計劃。

顯然,沒有用到任何索引,掃描的行數為32034,cost為3243.65。

mysql explain  format=json select * from t1  where rank1 =1 or rank2 = 2 or rank3 = 2\G*************************** 1. row ***************************EXPLAIN: {  “query_block”: {    “select_id”: 1,    “cost_info”: {      “query_cost”: “3243.65”    },    “table”: {      “table_name”: “t1”,      “access_type”: “ALL”,      “possible_keys”: [        “idx_rank1”,        “idx_rank2”,        “idx_rank3”      ],      “rows_examined_per_scan”: 32034,      “rows_produced_per_join”: 115,      “filtered”: “0.36”,      “cost_info”: {        “read_cost”: “3232.07”,        “eval_cost”: “11.58”,        “prefix_cost”: “3243.65”,        “data_read_per_join”: “49K”      },      “used_columns”: [        “id”,        “rank1”,        “rank2”,        “log_time”,        “prefix_uid”,        “desc1”,        “rank3”      ],      “attached_condition”: “((`ytt`.`t1`.`rank1` = 1) or (`ytt`.`t1`.`rank2` = 2) or (`ytt`.`t1`.`rank3` = 2))”    }  }}1 row in set, 1 warning (0.00 sec)

我們加上hint給相同的查詢,再次看看查詢計劃。

這個時候用到了index_merge,union了三個列。掃描的行數為1103,cost為441.09,明顯比之前的快了好幾倍。

mysql explain  format=json select /*+ index_merge(t1) */ * from t1  where rank1 =1 or rank2 = 2 or rank3 = 2\G*************************** 1. row ***************************EXPLAIN: {  “query_block”: {    “select_id”: 1,    “cost_info”: {      “query_cost”: “441.09”    },    “table”: {      “table_name”: “t1”,      “access_type”: “index_merge”,      “possible_keys”: [        “idx_rank1”,        “idx_rank2”,        “idx_rank3”      ],      “key”: “union(idx_rank1,idx_rank2,idx_rank3)”,      “key_length”: “5,5,5”,      “rows_examined_per_scan”: 1103,      “rows_produced_per_join”: 1103,      “filtered”: “100.00”,      “cost_info”: {        “read_cost”: “330.79”,        “eval_cost”: “110.30”,        “prefix_cost”: “441.09”,        “data_read_per_join”: “473K”      },      “used_columns”: [        “id”,        “rank1”,        “rank2”,        “log_time”,        “prefix_uid”,        “desc1”,        “rank3”      ],      “attached_condition”: “((`ytt`.`t1`.`rank1` = 1) or (`ytt`.`t1`.`rank2` = 2) or (`ytt`.`t1`.`rank3` = 2))”    }  }}1 row in set, 1 warning (0.00 sec)

我們再看下SQL D的計劃:

不加HINT,

mysql explain format=json select * from t1 where rank1 =100 and rank2 =100 and rank3 =100\G*************************** 1. row ***************************EXPLAIN: {  “query_block”: {    “select_id”: 1,    “cost_info”: {      “query_cost”: “534.34”    },    “table”: {      “table_name”: “t1”,      “access_type”: “ref”,      “possible_keys”: [        “idx_rank1”,        “idx_rank2”,        “idx_rank3”      ],      “key”: “idx_rank1”,      “used_key_parts”: [        “rank1”      ],      “key_length”: “5”,      “ref”: [        “const”      ],      “rows_examined_per_scan”: 555,      “rows_produced_per_join”: 0,      “filtered”: “0.07”,      “cost_info”: {        “read_cost”: “478.84”,        “eval_cost”: “0.04”,        “prefix_cost”: “534.34”,        “data_read_per_join”: “176”      },      “used_columns”: [        “id”,        “rank1”,        “rank2”,        “log_time”,        “prefix_uid”,        “desc1”,        “rank3”      ],      “attached_condition”: “((`ytt`.`t1`.`rank3` = 100) and (`ytt`.`t1`.`rank2` = 100))”    }  }}1 row in set, 1 warning (0.00 sec)

加了HINT,

mysql explain format=json select /*+ index_merge(t1)*/ * from t1 where rank1 =100 and rank2 =100 and rank3 =100\G*************************** 1. row ***************************EXPLAIN: {  “query_block”: {    “select_id”: 1,    “cost_info”: {      “query_cost”: “5.23”    },    “table”: {      “table_name”: “t1”,      “access_type”: “index_merge”,      “possible_keys”: [        “idx_rank1”,        “idx_rank2”,        “idx_rank3”      ],      “key”: “intersect(idx_rank1,idx_rank2,idx_rank3)”,      “key_length”: “5,5,5”,      “rows_examined_per_scan”: 1,      “rows_produced_per_join”: 1,      “filtered”: “100.00”,      “cost_info”: {        “read_cost”: “5.13”,        “eval_cost”: “0.10”,        “prefix_cost”: “5.23”,        “data_read_per_join”: “440”      },      “used_columns”: [        “id”,        “rank1”,        “rank2”,        “log_time”,        “prefix_uid”,        “desc1”,        “rank3”      ],      “attached_condition”: “((`ytt`.`t1`.`rank3` = 100) and (`ytt`.`t1`.`rank2` = 100) and (`ytt`.`t1`.`rank1` = 100))”    }  }}1 row in set, 1 warning (0.00 sec)

對比下以上兩個,加了HINT的比不加HINT的cost小了100倍。

總結下,就是說表的cardinality值影響這張的查詢計劃,如果這個值沒有正常更新的話,就需要手工加HINT了。相信MySQL未來的版本會帶來更多的HINT。

mysql資料庫如何優化?誰能給出點具體的解決方案?

1、explain:解釋sql的執行計劃,後邊的sql不執行

2、explain partitions :用於查看存在分區的表的執行計劃

3、explain extended:待驗證

4、show warnings:

5、show create table:查看錶的詳細的創建語句,便於用戶對錶進行優化

6、show indexes :產看錶的所有索引,show indexes from table_name,同樣也可以從information_schema.statistics表中獲得同樣的信息。cardinality列很重要,表示數據量。

7、show tables status: 查看資料庫表的底層大小以及表結構,同樣可以從information_schema.tables表中獲得底層表的信息。

8、show [global|session]status:可以查看mysql伺服器當前內部狀態信息。可以幫助卻行mysql伺服器的負載的各種指標。默認是session。同information_schema.global_status和information_schema.session_status

9、show [global|session] variables :查看當前mysql系統變數的值,其中一些值能影響到sql語句的執行方式。同information_schema.global_variables和information_schema.session_variables;

10、information_schema:包含的表的數量和mysql的版本有關係。

MySQL資料庫性能優化之分區分表分庫

分表是分散資料庫壓力的好方法。

分表,最直白的意思,就是將一個表結構分為多個表,然後,可以再同一個庫里,也可以放到不同的庫。

當然,首先要知道什麼情況下,才需要分表。個人覺得單表記錄條數達到百萬到千萬級別時就要使用分表了。

分表的分類

**1、縱向分表**

將本來可以在同一個表的內容,人為劃分為多個表。(所謂的本來,是指按照關係型資料庫的第三範式要求,是應該在同一個表的。)

分表理由:根據數據的活躍度進行分離,(因為不同活躍的數據,處理方式是不同的)

案例:

對於一個博客系統,文章標題,作者,分類,創建時間等,是變化頻率慢,查詢次數多,而且最好有很好的實時性的數據,我們把它叫做冷數據。而博客的瀏覽量,回複數等,類似的統計信息,或者別的變化頻率比較高的數據,我們把它叫做活躍數據。所以,在進行資料庫結構設計的時候,就應該考慮分表,首先是縱向分表的處理。

這樣縱向分表後:

首先存儲引擎的使用不同,冷數據使用MyIsam 可以有更好的查詢數據。活躍數據,可以使用Innodb ,可以有更好的更新速度。

其次,對冷數據進行更多的從庫配置,因為更多的操作時查詢,這樣來加快查詢速度。對熱數據,可以相對有更多的主庫的橫向分表處理。

其實,對於一些特殊的活躍數據,也可以考慮使用memcache ,redis之類的緩存,等累計到一定量再去更新資料庫。或者mongodb 一類的nosql 資料庫,這裡只是舉例,就先不說這個。

**2、橫向分表**

字面意思,就可以看出來,是把大的表結構,橫向切割為同樣結構的不同表,如,用戶信息表,user_1,user_2等。表結構是完全一樣,但是,根據某些特定的規則來劃分的表,如根據用戶ID來取模劃分。

分表理由:根據數據量的規模來劃分,保證單表的容量不會太大,從而來保證單表的查詢等處理能力。

案例:同上面的例子,博客系統。當博客的量達到很大時候,就應該採取橫向分割來降低每個單表的壓力,來提升性能。例如博客的冷數據表,假如分為100個表,當同時有100萬個用戶在瀏覽時,如果是單表的話,會進行100萬次請求,而現在分表後,就可能是每個表進行1萬個數據的請求(因為,不可能絕對的平均,只是假設),這樣壓力就降低了很多很多。

延伸:為什麼要分表和分區?

日常開發中我們經常會遇到大表的情況,所謂的大表是指存儲了百萬級乃至千萬級條記錄的表。這樣的表過於龐大,導致資料庫在查詢和插入的時候耗時太長,性能低下,如果涉及聯合查詢的情況,性能會更加糟糕。分表和表分區的目的就是減少資料庫的負擔,提高資料庫的效率,通常點來講就是提高表的增刪改查效率。

什麼是分表?

分表是將一個大表按照一定的規則分解成多張具有獨立存儲空間的實體表,我們可以稱為子表,每個表都對應三個文件,MYD數據文件,.MYI索引文件,.frm表結構文件。這些子表可以分布在同一塊磁碟上,也可以在不同的機器上。app讀寫的時候根據事先定義好的規則得到對應的子表名,然後去操作它。

什麼是分區?

分區和分表相似,都是按照規則分解表。不同在於分表將大表分解為若干個獨立的實體表,而分區是將數據分段劃分在多個位置存放,可以是同一塊磁碟也可以在不同的機器。分區後,表面上還是一張表,但數據散列到多個位置了。app讀寫的時候操作的還是大表名字,db自動去組織分區的數據。

**MySQL分表和分區有什麼聯繫呢?**

1、都能提高mysql的性高,在高並髮狀態下都有一個良好的表現。

2、分表和分區不矛盾,可以相互配合的,對於那些大訪問量,並且表數據比較多的表,我們可以採取分表和分區結合的方式(如果merge這種分表方式,不能和分區配合的話,可以用其他的分表試),訪問量不大,但是表數據很多的表,我們可以採取分區的方式等。

3、分表技術是比較麻煩的,需要手動去創建子表,app服務端讀寫時候需要計運算元表名。採用merge好一些,但也要創建子表和配置子表間的union關係。

4、表分區相對於分表,操作方便,不需要創建子表。

我們知道對於大型的互聯網應用,資料庫單表的數據量可能達到千萬甚至上億級別,同時面臨這高並發的壓力。Master-Slave結構只能對資料庫的讀能力進行擴展,寫操作還是集中在Master中,Master並不能無限制的掛接Slave庫,如果需要對資料庫的吞吐能力進行進一步的擴展,可以考慮採用分庫分表的策略。

**1、分表**

在分表之前,首先要選中合適的分表策略(以哪個字典為分表欄位,需要將數據分為多少張表),使數據能夠均衡的分布在多張表中,並且不影響正常的查詢。在企業級應用中,往往使用org_id(組織主鍵)做為分表欄位,在互聯網應用中往往是userid。在確定分表策略後,當數據進行存儲及查詢時,需要確定到哪張表裡去查找數據,

數據存放的數據表 = 分表欄位的內容 % 分表數量

**2、分庫**

分表能夠解決單表數據量過大帶來的查詢效率下降的問題,但是不能給資料庫的並發訪問帶來質的提升,面對高並發的寫訪問,當Master無法承擔高並發的寫入請求時,不管如何擴展Slave伺服器,都沒有意義了。我們通過對資料庫進行拆分,來提高資料庫的寫入能力,即所謂的分庫。分庫採用對關鍵字取模的方式,對資料庫進行路由。

數據存放的資料庫=分庫欄位的內容%資料庫的數量

**3、即分表又分庫**

資料庫分表可以解決單表海量數據的查詢性能問題,分庫可以解決單台資料庫的並發訪問壓力問題。

當資料庫同時面臨海量數據存儲和高並發訪問的時候,需要同時採取分表和分庫策略。一般分表分庫策略如下:

中間變數 = 關鍵字%(資料庫數量*單庫數據表數量)

庫 = 取整(中間變數/單庫數據表數量)

表 = (中間變數%單庫數據表數量)

實例:

1、分庫分表

很明顯,一個主表(也就是很重要的表,例如用戶表)無限制的增長勢必嚴重影響性能,分庫與分表是一個很不錯的解決途徑,也就是性能優化途徑,現在的案例是我們有一個1000多萬條記錄的用戶表members,查詢起來非常之慢,同事的做法是將其散列到100個表中,分別從members0到members99,然後根據mid分發記錄到這些表中,牛逼的代碼大概是這樣子:

複製代碼 代碼如下:

?php

for($i=0;$i 100; $i++ ){

//echo “CREATE TABLE db2.members{$i} LIKE db1.members

“;

echo “INSERT INTO members{$i} SELECT * FROM members WHERE mid%100={$i}

“;

}

?

2、不停機修改mysql表結構

同樣還是members表,前期設計的表結構不盡合理,隨著資料庫不斷運行,其冗餘數據也是增長巨大,同事使用了下面的方法來處理:

先創建一個臨時表:

/*創建臨時表*/

CREATE TABLE members_tmp LIKE members

然後修改members_tmp的表結構為新結構,接著使用上面那個for循環來導出數據,因為1000萬的數據一次性導出是不對的,mid是主鍵,一個區間一個區間的導,基本是一次導出5萬條吧,這裡略去了

接著重命名將新表替換上去:

/*這是個頗為經典的語句哈*/

RENAME TABLE members TO members_bak,members_tmp TO members;

就是這樣,基本可以做到無損失,無需停機更新表結構,但實際上RENAME期間表是被鎖死的,所以選擇在線少的時候操作是一個技巧。經過這個操作,使得原先8G多的表,一下子變成了2G多。

mysql中怎樣對大批量級的數據查詢進行優化

在我們使用MySQL資料庫時,比較常用也是查詢,包括基本查詢,關聯查詢,條件查詢等等,對於同一個操作,SQL語句的實現有很多種寫法,但是不同的寫法查詢的性能可能會有很大的差異。這裡主要介紹下select查詢優化的要點。

1. 使用慢查詢日誌去發現慢查詢。

2. 使用執行計划去判斷查詢是否正常運行。

3. 總是去測試你的查詢看看是否他們運行在最佳狀態下 –久而久之性能總會變化。

4. 避免在整個表上使用count(*),它可能鎖住整張表。

5. 使查詢保持一致以便後續相似的查詢可以使用查詢緩存。

6. 在適當的情形下使用GROUP BY而不是DISTINCT。

7. 在WHERE, GROUP BY和ORDER BY子句中使用有索引的列。

8. 保持索引簡單,不在多個索引中包含同一個列。

9. 有時候MySQL會使用錯誤的索引,對於這種情況使用USE INDEX。

10. 檢查使用SQL_MODE=STRICT的問題。

11.對於記錄數小於5的索引欄位,在UNION的時候使用LIMIT不是是用OR.

12. 為了 避免在更新前SELECT,使用INSERT ON DUPLICATE KEY或者INSERT IGNORE ,不要用UPDATE去實現。

3. 不要使用 MAX,使用索引欄位和ORDER BY子句。

14. 避免使用ORDER BY RAND().

15. LIMIT M,N實際上可以減緩查詢在某些情況下,有節制地使用。

16. 在WHERE子句中使用UNION代替子查詢。

17. 對於UPDATES(更新),使用 SHARE MODE(共享模式),以防止獨佔鎖。

18. 在重新啟動的MySQL,記得來溫暖你的資料庫,以確保您的數據在內存和查詢速度快。

19. 使用DROP TABLE,CREATE TABLE DELETE FROM從表中刪除所有數據。

20. 最小化的數據在查詢你需要的數據,使用*消耗大量的時間。

21. 考慮持久連接,而不是多個連接,以減少開銷。

22. 基準查詢,包括使用伺服器上的負載,有時一個簡單的查詢可以影響其他查詢。

23. 當負載增加您的伺服器上,使用SHOW PROCESSLIST查看慢的和有問題的查詢。

24. 在開發環境中產生的鏡像數據中 測試的所有可疑的查詢。

來源:PHP程序員雷雪松的博客

mysql對於大量數據,怎麼進行優化

1)調整伺服器的性能參數:key_buffer_size、Innodb_buffer_pool_size進行合理的配置

2)建立合適的索引

3)寫查詢語句用explain分析一下執行過程,核實一下執行計劃,是否按照自己的意願執行。

索引使要注意的地方:

1)索引不會包含有NULL值的列(使用索引的列設需要置默認值)2)使用短索引 3)不要在列上進行運算,即操作符號左端(使用函數)4) like語句操作5)不使用NOT IN和操作6)複合索引的建立7)選擇自己使用的索引: USE INDEX  , IGNORE INDEX  , FORCE INDEX  8) where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的(使用複合索引解決)

表掃描要注意的地方:

1)數據表很小,全表掃描比做索引鍵的查找來得快。當表的記錄總數小於10且比較短時通常這麼做。

2)沒有合適用於 ON 或 WHERE 分句的索引欄位。

3)讓索引欄位和常量值比較,MySQL已經計算(基於索引樹)到常量覆蓋了數據表的很大部分。

4)通過其他欄位使用了一個基數很小(很多記錄匹配索引鍵值)的索引鍵。這種情況下,MySQL認為使用索引鍵需要大量查找,還不如全表掃描來得更快。

5)使用合適的索引可以解決表掃描

6) 使用Limit有時候也可以解決表掃描

優化的地方太多了,一一列舉不完,你可以去這裡看一下,這裡面關於優化的知識有很多

,如果覺得說的有用就給個好評,寫這麼多怪不容易的,用了我一刻鐘的時間呀

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/241522.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 12:38
下一篇 2024-12-12 12:38

相關推薦

  • 如何修改mysql的埠號

    本文將介紹如何修改mysql的埠號,方便開發者根據實際需求配置對應埠號。 一、為什麼需要修改mysql埠號 默認情況下,mysql使用的埠號是3306。在某些情況下,我們需…

    編程 2025-04-29
  • Python讀取CSV數據畫散點圖

    本文將從以下方面詳細闡述Python讀取CSV文件並畫出散點圖的方法: 一、CSV文件介紹 CSV(Comma-Separated Values)即逗號分隔值,是一種存儲表格數據的…

    編程 2025-04-29
  • Python中讀入csv文件數據的方法用法介紹

    csv是一種常見的數據格式,通常用於存儲小型數據集。Python作為一種廣泛流行的編程語言,內置了許多操作csv文件的庫。本文將從多個方面詳細介紹Python讀入csv文件的方法。…

    編程 2025-04-29
  • Python 常用資料庫有哪些?

    在Python編程中,資料庫是不可或缺的一部分。隨著互聯網應用的不斷擴大,處理海量數據已成為一種趨勢。Python有許多成熟的資料庫管理系統,接下來我們將從多個方面介紹Python…

    編程 2025-04-29
  • openeuler安裝資料庫方案

    本文將介紹在openeuler操作系統中安裝資料庫的方案,並提供代碼示例。 一、安裝MariaDB 下面介紹如何在openeuler中安裝MariaDB。 1、更新軟體源 sudo…

    編程 2025-04-29
  • 如何用Python統計列表中各數據的方差和標準差

    本文將從多個方面闡述如何使用Python統計列表中各數據的方差和標準差, 並給出詳細的代碼示例。 一、什麼是方差和標準差 方差是衡量數據變異程度的統計指標,它是每個數據值和該數據值…

    編程 2025-04-29
  • Python多線程讀取數據

    本文將詳細介紹多線程讀取數據在Python中的實現方法以及相關知識點。 一、線程和多線程 線程是操作系統調度的最小單位。單線程程序只有一個線程,按照程序從上到下的順序逐行執行。而多…

    編程 2025-04-29
  • Python爬取公交數據

    本文將從以下幾個方面詳細闡述python爬取公交數據的方法: 一、準備工作 1、安裝相關庫 import requests from bs4 import BeautifulSou…

    編程 2025-04-29
  • Python兩張表數據匹配

    本篇文章將詳細闡述如何使用Python將兩張表格中的數據匹配。以下是具體的解決方法。 一、數據匹配的概念 在生活和工作中,我們常常需要對多組數據進行比對和匹配。在數據量較小的情況下…

    編程 2025-04-29
  • Python數據標準差標準化

    本文將為大家詳細講述Python中的數據標準差標準化,以及涉及到的相關知識。 一、什麼是數據標準差標準化 數據標準差標準化是數據處理中的一種方法,通過對數據進行標準差標準化可以將不…

    編程 2025-04-29

發表回復

登錄後才能評論