成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

MySQL億級數據數據庫優化方案測試-銀行交易流水記錄的查詢

數據庫 MySQL
對MySQL的性能和億級數據的處理方法思考,以及分庫分表到底該如何做,在什么場景比較合適?

 [[267270]]

對MySQL的性能和億級數據的處理方法思考,以及分庫分表到底該如何做,在什么場景比較合適?

比如銀行交易流水記錄的查詢

限鹽少許,上實際實驗過程,以下是在實驗的過程中做一些操作,以及踩過的一些坑,我覺得坑對于讀者來講是非常有用的。

首先:建立一個現金流量表,交易歷史是各個金融體系下使用率***,歷史存留數據量***的數據類型。現金流量表的數據搜索,可以根據時間范圍,和個人,以及金額進行搜索。

-- 建立一張 現金流量表 

  1. DROP TABLE IF EXISTS `yun_cashflow`;  
  2. CREATE TABLE `yun_cashflow` (  
  3.   `id` bigint(20) NOT NULL AUTO_INCREMENT,  
  4.   `userid` int(11) DEFAULT NULL,  
  5.   `type` int(11) DEFAULT NULL COMMENT '1、入賬,2提現',  
  6.   `operatoruserid` int(11) DEFAULT NULL COMMENT '操作員ID',  
  7.   `withdrawdepositid` bigint(20) DEFAULT NULL COMMENT '提現ID',  
  8.   `money` double DEFAULT NULL COMMENT '錢數',  
  9.   `runid` bigint(20) DEFAULT NULL COMMENT '工單ID',  
  10.   `createtime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  
  11.   PRIMARY KEY (`id`)  
  12. ENGINE=InnoDB AUTO_INCREMENT=63 DEFAULT CHARSET=utf8

然后開始造1個億的數據進去。

-- 循環插入 

  1. drop PROCEDURE test_insert;  
  2. DELIMITER;;  
  3. CREATE PROCEDURE test_insert()  
  4. begin   
  5. declare num int;   
  6. set num=0 
  7.         while num < 10000 do  
  8.             insert into yun_cashflow(userid,type,operatoruserid,withdrawdepositid,money) values(FLOOR(7 + (RAND() * 6))+FLOOR(22 + (RAND() * 9)),1,FLOOR(97 + (RAND()  
  9.  
  10. * 6))+FLOOR(2 + (RAND() * 9)),FLOOR(17 + (RAND() * 6))+FLOOR(2 + (RAND() * 9)),FLOOR(5 + (RAND() * 6))+FLOOR(2 + (RAND() * 9)));  
  11.             set numnum=num+1;  
  12.         end while;  
  13.   END;;  
  14. call test_insert(); 

 坑一:

這個存儲過程建立好了之后,發現插入數據特別的慢,一天一晚上也插入不到100萬條數據,平均每秒40~60條數據,中間我停過幾次,以為是隨機函數的問題,都變成常數,但效果一樣,還是很慢,當時讓我對這個MySQL數據庫感覺到悲觀,畢竟Oracle用慣了,那插速是真的很快,不過功夫不負有心人,原來可以用另外一種寫法造數據,速度很快,上代碼。 

  1. INSERT INTO example  
  2. (example_id, name, value, other_value)  
  3. VALUES  
  4. (100, 'Name 1', 'Value 1', 'Other 1'),  
  5. (101, 'Name 2', 'Value 2', 'Other 2'),  
  6. (102, 'Name 3', 'Value 3', 'Other 3'),  
  7. (103, 'Name 4', 'Value 4', 'Other 4'); 

就是在循環里,用這種格式造很多數據,VALUES后面以,隔開,然后把數據寫上去,我用Excel造了1萬條數據,按照語句格式粘貼了出來,就變成每循環一次,就1萬條數據,這樣沒多久1億數據就造好了。 

  1. select count(*) from yun_cashflow 

我還比較好奇,8個字段1億條數據,到底占了多大的地方,通過以下語句找到數據的路徑。 

  1. show global variables like "%datadir%"; 

通過查看文件,是7.78GB,看來如果字段不是很多,數據量大的話,其實不是什么問題,這其實作為架構師來講,在估算機器配置硬盤冗余的時候,這是最簡單直接粗暴的換算思路。

行了,表建完了,各種實驗開始

首先,啥條件不加看看咋樣。

呵呵了,Out of memory,看來這個查詢是真往內存里整,內存整冒煙了,看來7.8G的數據是往內存里放,我內存沒那么大導致的。

資金流水一般會按照時間進行查詢,看看這速度到底怎樣。 

  1. select * from yun_cashflow  where createtime between '2018-10-23 09:06:58' and '2018-10-23 09:06:59'  

我去,腦補一下,當你拿這支付寶查歷史資金明細的時候,56條信息,103.489秒,也就是將近2分鐘的查詢速度,你會是怎樣的體驗。哦 哦,不對,這個還沒加用條件,那下面單獨試試某個用戶不限時間范圍的條件是怎樣的。 

  1. select count(*) from yun_cashflow where userid=21 

也是將近1分半的速度,那在試試金額的條件。 

  1. select count(*) from yun_cashflow where money<62 and userid=32 

同樣都是將近一分半的時間。

那把兩個條件做下級聯,看看效果會是怎樣。

一樣,也是將近1分半的時間。

小總結一:在不加索引的情況下,無論單獨,還是聯合條件查詢,結果都是1分多鐘不到2分鐘。

好吧,那就加上索引試試,看看到底會有啥樣奇跡發生。

給用戶加索引 

  1. ALTER TABLE yun_cashflow ADD INDEX index_userid (userid) `

給金額加索引 

  1. ALTER TABLE yun_cashflow ADD INDEX index_money (money) 

給時間加索引 

  1. ALTER TABLE yun_cashflow ADD INDEX index_createtime (createtime) 

小總結二: 建立索引的時間平均在1400秒左右,大概在23分鐘左右。

索引都建立完了,在開始以前的條件查詢,看看效果。

1、時間范圍查詢 

  1. select * from yun_cashflow  where createtime between '2018-10-23 09:06:58' and '2018-10-23 09:06:59' 

2、用戶查詢與錢的聯合查詢

3、用戶查詢與錢與時間三個條件的聯合查詢 

  1. select * from yun_cashflow where money<62 and userid=32 and  createtime between '2018-10-22 09:06:58' and '2018-10-23 09:06:59' 

小總結三:建立完索引后,這種級聯性質的查詢,速度基本都很快,數據量不大的情況下,基本不會超過一秒。

由于時間的范圍返回是56條數據,數據量比較小,所以速度快可能與這個有關,那實驗下條件多的數據效果會是什么樣。

先試試加完索引, 金額條件的效果。

2千5百萬的數據,返回時間為11.460秒。

加一個用戶數量比較多的條件 UserID=21

返回1000多萬的數據,用了6秒

在找一個用戶數量比較少的userid=34

返回4000多條,用不到1秒。

小總結四:條件返回的數據統計量越多,速度就越慢,超過1000萬就慢的離譜,1秒左右就是100萬的量才行。

那。。。。。。。。。。。。咱們程序猿都知道,我們在做數據的時候,都要用到分頁。分頁一般會用到LIMIT,比如每頁10行,第二頁就是LIMIT 10,10,得試試在分頁的時候,哪些頁的情況下,會是什么樣的效果呢?

  •  limit在1千時候速度
  •  limit在1百萬時候速度
  •  limit在1千萬時候速度

小總結五:LIMIT 參數1,參數2  在隨著參數1(開始索引)增大時候,這個速度就會越來越慢,如果要求1秒左右返回時候的速度是100萬數據,在多在大就慢了,也就是,如果10條一頁,當你到第10萬頁之后,就會越來越慢。如果到30萬頁之后,可能就會到不到一般系統的3秒要求了。

數據庫都建上索引了,那我插數據速度有沒有影響呢,那試試

也就是說100條數據插了將近5秒,平均每秒插20條。

小總結六:也就是說,按照這樣的速度插入,并發量一但大的情況下,操作起來會很慢。所以在有索引的條件下插入數據,要么索引失效,要么插入會特別慢。

分庫分表的思維,一個大表返回那么多數據慢,那我把它變成若干張表,然后每張表count(*)后,我統計累加一下,一合計,就是所有數據的查詢結果的條數,然后就是到第多少頁,我先算一下這頁在哪個庫,哪張表,在從那張表讀不就完了。通過之前 的總結,100萬數據返回為1秒,所以就一張表里放100萬個數據,1億的數據就100張表。 

  1. BEGIN   
  2.         DECLARE `@i` int(11);      
  3.         DECLARE `@createSql` VARCHAR(2560);   
  4.         DECLARE `@createIndexSql1` VARCHAR(2560);   
  5.         DECLARE `@createIndexSql2` VARCHAR(2560);  
  6.         DECLARE `@createIndexSql3` VARCHAR(2560);  
  7.         set `@i`=0;   
  8.         WHILE  `@i`< 100 DO                  
  9.                             SET @createSql = CONCAT('CREATE TABLE IF NOT EXISTS yun_cashflow_',`@i`,'(  
  10. `id` bigint(20) NOT NULL AUTO_INCREMENT,  
  11.                                 `userid` int(11) DEFAULT NULL,  
  12.                                 `type` int(11) DEFAULT NULL  ,  
  13.                                 `operatoruserid` int(11) DEFAULT NULL  ,  
  14.                                 `withdrawdepositid` bigint(20) DEFAULT NULL  ,  
  15.                                 `money` double DEFAULT NULL  ,  
  16.                                 `runid` bigint(20) DEFAULT NULL  ,  
  17.                                 `createtime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  
  18.                                 PRIMARY KEY (`id`)  
  19.                                 )'  
  20.                             );   
  21.                             prepare stmt from @createSql;   
  22.                             execute stmt;           

-- 創建索引   

  1.   set @createIndexSql1  = CONCAT('create index `t_money` on yun_cashflow_',`@i`,'(`money`);');  
  2.                             prepare stmt1 from @createIndexSql1;   
  3.                             execute stmt1;   
  4.                             set @createIndexSql2  = CONCAT('create index `t_userid` on yun_cashflow_',`@i`,'(`userid`);');  
  5.                             prepare stmt2 from @createIndexSql2;   
  6.                             execute stmt2;   
  7. SET `@i`= `@i`+1;   
  8.             END WHILE;  
  9. END 

表建完了,庫里的效果是醬樣的。

是不是很酷,這表分的,絕了,滿庫全是表。那還得往每張表里整100萬的數據。這部分代碼就不寫了,可以參考前面的改,相信能把文章看到這的都是懂行的人,也是對這方面有一腚追求的人。

坑二:我高估了我的計算機的并行計算能力,當我啟用100個線程同時玩我自己電腦的數據庫連接的時候,到后期給我反饋的結果是這樣的。

說白了,連接滿了,超時,數據庫都不給我返回值了,所以這種實驗,不找100臺機器,也別可一臺機器去霍霍,因為如果能快,那個1個億的大表,返回的也不會慢。這時候拼的就是計算能力了,都在一臺機器上去做實驗,會讓你懷疑人生的。

那咋辦, 這地方我就假裝返回都是1000毫秒,也就1秒,然后每個線程都在1秒的時候都給我返回值,這個值我寫死,可以看看多線程分布式統計count的效果。

***總體耗時,就是***那個返回時間最長的線程返回的時間,所以理論上100個線程同時啟動,應該在1秒完成,但線程這玩意有快有慢,所以1秒多一點,也是可以接受的。如果碰上都是機器性能好的時候,所有數據庫返回都在1秒以內,那么也就是1秒了。

這個多線程編程可以試試類似Java的countDownLatch/AKKA 將異步多線程結果同步返回。

***是在數據庫數據量比較大的時候,通過MySQL以上的特性,進行不同場景應用的思考。

場景:銀行交易流水記錄的查詢

  1.  根據小總結六的特性,操作表和歷史查詢表一定要時間可以分開,由于帶索引的歷史表,插入會很慢,所以要插入到操作表內,操作表和歷史表的字段是一樣的。
  2.  根據小總結二特性,然后固定某個時間點,比如半夜12點,或者固定日期,或者選擇非交易查詢活躍的時間,把操作表里的數據往歷史表里插一下,由于重建索引也用不了太久,一樣半個小時左右。讓兩種表并存。還有另外一種策略,由于流水主要以時間做為排序對象,可以按照時間順序,也就是ID自增長的順序進行分庫分表,就像試驗的那樣,100萬左右條數據一張表,另外在做一張時間范圍的索引表,如下: 
  1. CreateTimeIndexTable  
  2. ID  TableName   CreateTimeStart CreateTimeEnd  
  3. 1   yun_cashflow_1  2018-10-22 09:06:58 2018-10-26 09:06:58  
  4. 2   yun_cashflow_2  2018-10-26 09:06:58 2018-10-29 09:06:58  
  5. 3   yun_cashflow_3  2018-11-12 09:06:58 2018-11-22 09:06:58  
  6. 4   yun_cashflow_4  2018-11-22 09:06:58 2018-11-26 09:06:58 

當遇見這樣語句需求的時候: 

  1. select * from yun_cashflow where money<62 and userid=32 and  createtime between '2018-10-27 09:06:58' and '2018-10-28 09:06:59' 

1)、就改寫成這樣的順序 

  1. select TableName from CreateTimeIndexTable where CreateTimeStart>  '2018-10-27 09:06:58' and CreateTimeEnd < '2018-10-28 09:06:59' 

2)、當得到TableName的時候,結果是yun_cashflow_2,在進行語句的查詢 

  1. select * from yun_cashflow_2 where money<62 and userid=32 and  createtime between '2018-10-27 09:06:58' and '2018-10-28 09:06:59' 

這樣,兩遍就可以查詢到結果。

不過也有可能查詢的結果是多個,比如 

  1. select TableName from CreateTimeIndexTable where CreateTimeStart>  '2018-10-27 09:06:58' and CreateTimeEnd < '2018-11-13 09:06:59' 

yun_cashflow_2,和yun_cashflow_3,這個時候,就需要把兩個表的結果都查詢出來,進行merge。相信程序員們對兩個表的結果集合并邏輯都不是什么難事,這地方不多解釋。

這樣做的好處,主要是每次重建索引的時候,就不用整個1個億的大表進行重建,而是只重建最近的1百萬的那張分出來的表,速度會很快的。

    3.  根據小總結一和小總結三的特性,把關鍵的字段加上索引,用戶,時間,這樣保證查詢的速度。

    4.  根據小總結四的特性,盡量限制查詢結果的數量范圍,比如,單個人查自己的交易明細,可以限制范圍,比如查詢時間范圍不超過三個月,或半年,或一年。 

責任編輯:龐桂玉 來源: 數據庫開發
相關推薦

2011-04-20 14:28:38

SQL優化

2021-06-29 08:12:22

MySQL數據分頁數據庫

2014-07-18 09:33:53

數據庫數據庫優化

2011-03-03 10:32:07

Mongodb億級數據量

2019-03-05 10:16:54

數據分區表SQLserver

2024-08-22 14:16:08

2013-01-04 10:00:12

MySQL數據庫數據庫查詢優化

2010-05-13 10:47:44

MySQL數據庫查詢

2010-06-10 10:15:50

MySQL數據庫查詢

2010-05-20 18:12:37

MySQL數據庫查詢

2021-03-11 10:55:41

MySQL數據庫索引

2010-06-11 12:32:57

MySQL數據庫查詢

2010-06-17 09:15:02

MySQL數據庫查詢

2011-07-06 14:12:20

MySQLPercona

2011-03-09 08:53:02

MySQL優化集群

2011-07-06 10:49:50

MySQL優化

2010-05-27 17:16:20

MySQL數據庫

2019-05-28 09:31:05

Elasticsear億級數據ES

2011-03-08 08:49:55

MySQL優化單機

2021-03-16 07:41:00

數據分頁優化
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩中文字幕在线 | 欧美日韩在线一区二区三区 | 久久久久久久久精 | 亚洲欧美网站 | 99精品视频在线观看免费播放 | 国产高清91| 精品一区二区三区在线观看 | 国产中文字幕亚洲 | 91精品久久久久久久久中文字幕 | 欧美一区二区三区在线观看视频 | 欧美999| www.日本在线观看 | 欧洲亚洲一区二区三区 | 日韩精品中文字幕一区二区三区 | 亚洲精品在线视频 | 国产一级一级毛片 | 国产成人精品a视频一区www | 久久一二区| 日韩中文字幕在线视频观看 | 99精品九九 | 一区二区三区免费看 | 成人免费视频网 | 精品一区二区三区在线视频 | 久久成人综合 | 日韩在线一区二区 | 久久国产一区二区三区 | 天天操夜夜操 | 91麻豆蜜桃一区二区三区 | 国产精品v | 午夜性色a√在线视频观看9 | 亚洲高清在线播放 | 91麻豆精品国产91久久久更新资源速度超快 | v亚洲 | 免费观看www7722午夜电影 | 日韩中文字幕在线播放 | 欧美在线观看一区 | 久久国产精品视频 | 欧洲高清转码区一二区 | 欧美a在线 | 成人黄色a| 亚洲综合中文字幕在线观看 |