<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:一千萬數(shù)據(jù),怎么快速查詢?

          共 8831字,需瀏覽 18分鐘

           ·

          2022-03-09 22:10

          上一篇:字節(jié)跳動面試經(jīng)驗總結,已順利拿到offer!

          來自:juejin.cn/post/6863668253898735629

          前言

          • 面試官:來說說,一千萬的數(shù)據(jù),你是怎么查詢的?

          • B哥:直接分頁查詢,使用limit分頁。

          • 面試官:有實操過嗎?

          • B哥:肯定有呀

          此刻獻上一首《涼涼》

          也許有些人沒遇過上千萬數(shù)據(jù)量的表,也不清楚查詢上千萬數(shù)據(jù)量的時候會發(fā)生什么。

          今天就來帶大家實操一下,這次是基于MySQL 5.7.26做測試

          準備數(shù)據(jù)

          沒有一千萬的數(shù)據(jù)怎么辦?

          創(chuàng)建唄

          代碼創(chuàng)建一千萬?那是不可能的,太慢了,可能真的要跑一天??梢圆捎脭?shù)據(jù)庫腳本執(zhí)行速度快很多。

          創(chuàng)建表

          CREATE TABLE `user_operation_log`  (
            `id` int(11) NOT NULL AUTO_INCREMENT,
            `user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `ip` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `op_data` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr3` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr4` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr5` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr6` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr7` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr8` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr9` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr10` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr11` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            `attr12` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
            PRIMARY KEY (`id`) USING BTREE
          ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

          創(chuàng)建數(shù)據(jù)腳本

          采用批量插入,效率會快很多,而且每1000條數(shù)就commit,數(shù)據(jù)量太大,也會導致批量插入效率慢

          DELIMITER ;;
          CREATE PROCEDURE batch_insert_log()
          BEGIN
            DECLARE i INT DEFAULT 1;
            DECLARE userId INT DEFAULT 10000000;
           set @execSql = 'INSERT INTO `test`.`user_operation_log`(`user_id`, `ip`, `op_data`, `attr1`, `attr2`, `attr3`, `attr4`, `attr5`, `attr6`, `attr7`, `attr8`, `attr9`, `attr10`, `attr11`, `attr12`) VALUES';
           set @execData = '';
            WHILE i<=10000000 DO
             set @attr = "'測試很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長的屬性'";
            set @execData = concat(@execData, "(", userId + i, ", '10.0.69.175', '用戶登錄操作'"",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ")");
            if i % 1000 = 0
            then
               set @stmtSql = concat(@execSql, @execData,";");
              prepare stmt from @stmtSql;
              execute stmt;
              DEALLOCATE prepare stmt;
              commit;
              set @execData = "";
             else
               set @execData = concat(@execData, ",");
             end if;
            SET i=i+1;
            END WHILE;

          END;;
          DELIMITER ;

          哥的電腦配置比較低:win10 標壓渣渣i5 讀寫約500MB的SSD

          由于配置低,本次測試只準備了3148000條數(shù)據(jù),占用了磁盤5G(還沒建索引的情況下),跑了38min,電腦配置好的同學,可以插入多點數(shù)據(jù)測試

          SELECT count(1) FROM `user_operation_log`

          返回結果:3148000

          三次查詢時間分別為:

          • 14060 ms

          • 13755 ms

          • 13447 ms

          普通分頁查詢

          MySQL 支持 LIMIT 語句來選取指定的條數(shù)數(shù)據(jù), Oracle 可以使用 ROWNUM 來選取。

          MySQL分頁查詢語法如下:

          SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset

          • 第一個參數(shù)指定第一個返回記錄行的偏移量
          • 第二個參數(shù)指定返回記錄行的最大數(shù)目
          下面我們開始測試查詢結果:

          SELECT * FROM `user_operation_log` LIMIT 10000, 10

          查詢3次時間分別為:
          • 59 ms

          • 49 ms

          • 50 ms

          這樣看起來速度還行,不過是本地數(shù)據(jù)庫,速度自然快點。

          換個角度來測試

          相同偏移量,不同數(shù)據(jù)量

          SELECT * FROM `user_operation_log` LIMIT 10000, 10
          SELECT * FROM `user_operation_log` LIMIT 10000, 100
          SELECT * FROM `user_operation_log` LIMIT 10000, 1000
          SELECT * FROM `user_operation_log` LIMIT 10000, 10000
          SELECT * FROM `user_operation_log` LIMIT 10000, 100000
          SELECT * FROM `user_operation_log` LIMIT 10000, 1000000

          查詢時間如下:
          圖片

          從上面結果可以得出結束:數(shù)據(jù)量越大,花費時間越長

          相同數(shù)據(jù)量,不同偏移量

          SELECT * FROM `user_operation_log` LIMIT 100, 100
          SELECT * FROM `user_operation_log` LIMIT 1000, 100
          SELECT * FROM `user_operation_log` LIMIT 10000, 100
          SELECT * FROM `user_operation_log` LIMIT 100000, 100
          SELECT * FROM `user_operation_log` LIMIT 1000000, 100

          圖片

          從上面結果可以得出結束:偏移量越大,花費時間越長

          SELECT * FROM `user_operation_log` LIMIT 100, 100
          SELECT id, attr FROM `user_operation_log` LIMIT 100, 100

          如何優(yōu)化

          既然我們經(jīng)過上面一番的折騰,也得出了結論,針對上面兩個問題:偏移大、數(shù)據(jù)量大,我們分別著手優(yōu)化

          優(yōu)化偏移量大問題

          采用子查詢方式

          我們可以先定位偏移位置的 id,然后再查詢數(shù)據(jù)

          SELECT * FROM `user_operation_log` LIMIT 1000000, 10SELECT id FROM `user_operation_log` LIMIT 1000000, 1SELECT * FROM `user_operation_log` WHERE id >= (SELECT id FROM `user_operation_log` LIMIT 1000000, 1) LIMIT 10

          查詢結果如下:
          圖片

          從上面結果得出結論:

          • 第一條花費的時間最大,第三條比第一條稍微好點

          • 子查詢使用索引速度更快

          缺點:只適用于id遞增的情況

          id非遞增的情況可以使用以下寫法,但這種缺點是分頁查詢只能放在子查詢里面

          注意:某些 mysql 版本不支持在 in 子句中使用 limit,所以采用了多個嵌套select

          SELECT * FROM `user_operation_log` WHERE id IN (SELECT t.id FROM (SELECT id FROM `user_operation_log` LIMIT 1000000, 10) AS t)

          采用 id 限定方式

          這種方法要求更高些,id必須是連續(xù)遞增,而且還得計算id的范圍,然后使用 between,sql如下

          SELECT * FROM `user_operation_log` WHERE id between 1000000 AND 1000100 LIMIT 100

          SELECT * FROM `user_operation_log` WHERE id >= 1000000 LIMIT 100

          查詢結果如下:
          圖片
          從結果可以看出這種方式非???/span>
          注意:這里的 LIMIT 是限制了條數(shù),沒有采用偏移量

          優(yōu)化數(shù)據(jù)量大問題

          返回結果的數(shù)據(jù)量也會直接影響速度

          SELECT * FROM `user_operation_log` LIMIT 1, 1000000

          SELECT id FROM `user_operation_log` LIMIT 1, 1000000

          SELECT id, user_id, ip, op_data, attr1, attr2, attr3, attr4, attr5, attr6, attr7, attr8, attr9, attr10, attr11, attr12 FROM `user_operation_log` LIMIT 1, 1000000

          查詢結果如下:
          圖片

          從結果可以看出減少不需要的列,查詢效率也可以得到明顯提升

          第一條和第三條查詢速度差不多,這時候你肯定會吐槽,那我還寫那么多字段干啥呢,直接 * 不就完事了

          注意本人的 MySQL 服務器和客戶端是在_同一臺機器_上,所以查詢數(shù)據(jù)相差不多,有條件的同學可以測測客戶端與MySQL分開

          SELECT * 它不香嗎?

          在這里順便補充一下為什么要禁止 SELECT *。難道簡單無腦,它不香嗎?

          主要兩點:

          結束

          最后還是希望大家自己去實操一下,肯定還可以收獲更多!!

          創(chuàng)建腳本我給你準備好了,你還在等什么?。?!
          感謝您的閱讀,也歡迎您發(fā)表關于這篇文章的任何建議,關注我,技術不迷茫!小編到你上高速。 
              · END ·
          最后,關注公眾號互聯(lián)網(wǎng)架構師,在后臺回復:2T,可以獲取我整理的 Java 系列面試題和答案,非常齊全。


          正文結束


          推薦閱讀 ↓↓↓

          1.救救大齡碼農(nóng)!45歲程序員在國務院網(wǎng)站求助總理!央媒網(wǎng)評來了...

          2.如何才能成為優(yōu)秀的架構師?

          3.從零開始搭建創(chuàng)業(yè)公司后臺技術棧

          4.程序員一般可以從什么平臺接私活?

          5.37歲程序員被裁,120天沒找到工作,無奈去小公司,結果懵了...

          6.IntelliJ IDEA 2019.3 首個最新訪問版本發(fā)布,新特性搶先看

          7.這封“領導痛批95后下屬”的郵件,句句扎心!

          8.15張圖看懂瞎忙和高效的區(qū)別!


          瀏覽 32
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  美日韩一级黄色片中文字幕 | 99超碰在线观看 | 在线观看色情网站 | av毛片网 | 成人毛片18女人毛片免费黑人看 |