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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

震惊!阿里的程序员竟被一个简单的 SQL 查询难住了!

發布時間:2024/8/23 数据库 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 震惊!阿里的程序员竟被一个简单的 SQL 查询难住了! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者 | 唐磊

責編 | Carol

來源 | 程序猿石頭

封圖 |?CSDN 付費下載于視覺中國

最近工作上遇到一個”神奇”的問題,或許對大家有幫助,因此形成本文。

問題大概是,我有兩個表 TableA,TableB,其中 TableA 表大概百萬行級別(存量業務數據),TableB 表幾行(新業務場景, 數據還未膨脹起來),語義上 ?TableA.columnA = TableB.columnA,其中?columnA?上建立了索引,但查詢的時候確巨慢無比, 基本上到5-6 秒,明顯跟預期不符合。

下面我以一個具體的例子來說明吧,模擬其中的 SQL 查詢場景、

場景重現

  • user_info?表, 為了場景盡量簡單, 我只 mock 了其中的三列數據。

  • user_score?表,其中?uid?和?user_info.uid?語義一致。

  • 其中數據情況如下,都是很常見的場景。

  • 索引情況是

  • 查詢業務場景: 已知?user_score.id, 需要關聯查詢對應user_info的信息, (大家先忽略這個具體業務場景是否合理哈)。那么對應的 SQL 很自然的如下:

請忽略其中的數據,我剛開始 mock 了 100W,然后又重復導入了兩遍, 因此數據有一些重復。300W 數據, 最后查詢出來也是 1.18 秒,按道理應該更快的。老規矩?explain?看看啥情況?

發現?user_info表沒用上索引, 全表掃描近 300W 數據? 現象是這樣, 為什么呢?

你不妨思考一下, 如果你遇到這種場景, 應該怎么去排查?

(分割線, 花 10 秒想想?)


我當時也是”一頓操作猛如虎”,然并卵? 嘗試了什么多種 sql 寫法來完成這個操作,比如更換Join表的順序(驅動表/被驅動表),?再比如用子查詢。最終,還是沒有結果。但直接單表查詢寫 SQL 確能用上索引。

問題解決

嘗試更換檢索條件,比如更換 uid 直接關聯查詢,索引仍然用不上, 差點放棄了都。在準備求助 DBA 前, 看了下表的建表語句。

完全有理由懷疑因為字符集不一致的問題導致索引失效的問題了。
于是修改了小表(真實線上環境可別亂操作)的字符集與大表一致, 再測試下。

mysql> select * from user_score us-> inner join user_info ui on us.uid = ui.uid-> where us.id = 5; +----+-----------+-------+---------+-----------+---------+ | id | uid | score | id | uid | name | +----+-----------+-------+---------+-----------+---------+ | 5 | 111111111 | 100 | 1 | 111111111 | tanglei | | 5 | 111111111 | 100 | 3685399 | 111111111 | tanglei | | 5 | 111111111 | 100 | 3685400 | 111111111 | tanglei | | 5 | 111111111 | 100 | 3685401 | 111111111 | tanglei | | 5 | 111111111 | 100 | 3685402 | 111111111 | tanglei | | 5 | 111111111 | 100 | 3685403 | 111111111 | tanglei | +----+-----------+-------+---------+-----------+---------+ 6 rows in set (0.00 sec)mysql> explain-> select * from user_score us-> inner join user_info ui on us.uid = ui.uid-> where us.id = 5; +----+-------------+-------+-------+-------------------+-----------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+-------------------+-----------+---------+-------+------+-------+ | 1 | SIMPLE | us | const | PRIMARY,index_uid | PRIMARY | 4 | const | 1 | NULL | | 1 | SIMPLE | ui | ref | index_uid | index_uid | 194 | const | 6 | NULL | +----+-------------+-------+-------+-------------------+-----------+---------+-------+------+-------+ 2 rows in set (0.00 sec)

果然 work 了。

挖掘根因


其實深究原因,就是網上各種 MySQL軍規/規約所提到的, “索引列不要參與計算”。?這次這個 case,,如果知道?explain extended + show warnings?這個工具的話,(以前都不知道explain后面還能加?extended?參數),?可能就盡早”恍然大悟”了。(最新的 MySQL 8.0版本貌似不需要另外加這個關鍵字)。

看下效果。(啊, 我還得把字符集改回去!!!)

mysql> explain extended select * from user_score us inner join user_info ui on us.uid = ui.uid where us.id = 5; +----+-------------+-------+-------+-------------------+---------+---------+-------+---------+----------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+-------+-------------------+---------+---------+-------+---------+----------+-------------+ | 1 | SIMPLE | us | const | PRIMARY,index_uid | PRIMARY | 4 | const | 1 | 100.00 | NULL | | 1 | SIMPLE | ui | ALL | NULL | NULL | NULL | NULL | 2989934 | 100.00 | Using where | +----+-------------+-------+-------+-------------------+---------+---------+-------+---------+----------+-------------+ 2 rows in set, 1 warning (0.00 sec) mysql> show warnings; +-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Note | 1003 | /* select#1 */ select '5' AS `id`,'111111111' AS `uid`,'100' AS `score`,`test`.`ui`.`id` AS `id`,`test`.`ui`.`uid` AS `uid`,`test`.`ui`.`name` AS `name` from `test`.`user_score` `us` join `test`.`user_info` `ui` where (('111111111' = convert(`test`.`ui`.`uid` using utf8mb4))) | +-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)

(滑動看右邊)

索引列參與計算了,每次都要根據字符集去轉換, 全表掃描,你說能快得起來么?

至于這個問題為什么會發生? 綜合來看, 就是因為歷史原因,老業務場景中的原表是假?utf8, 新業務新表采用了真?utf8mb4。

  • 考慮新表的時候, 忽略和原庫字符集的比較. 其實, 發現庫里面的不同表可能都有不同的字符集, 不同人建的時候可能都依據個人喜好去選擇了不同的字符集. 由此可見,?開發規范有多重要.

  • 雖然知道索引列不能參與計算, 但這個場景下都是相同的類型, ?varchar(64)?最終查詢過程中仍然發生了類型轉換. 因此需要把字段字符集不一致等同于字段類型不一致.

  • 如果這個 case, 利用?fail-fast?的理念的話, 發現不一致, 直接不讓 join 會不會更好? (就像?char v.s varchar?不能 join 一樣).

  • 說明:?本文測試場景基于 MySQL 5.6,?另外,?本文案例只是為了說明問題,?其中的 SQL 并不規范(例如盡量別用 select * 之類的), 請勿模仿(模仿了我也不負責). ?為了寫本文, 可花了不少時間, 建 DB, mock數據, 包括排版公眾號(啊,公眾號后臺對代碼格式還是不友好, markdown 轉來代碼格式還是有問題)等等, 如果覺得有用, 還望你幫忙"在看", "轉發". 最后留一個思考題供討論, 歡迎留言說出你的看法。

    留一道思考題

    你能解釋如下情況嗎? 查詢結果表現為何不一致???注意一下 SQL 的執行順序, 查詢優化器工作流程,以及其中的?Using join buffer (Block Nested Loop), 可以多看看 [MySQL 官方手冊](https://dev.mysql.com/doc/refman/5.6/en/) 深入了解背后的過程和原理。

    作者簡介

    唐磊,碼農@阿里云,碩士畢業于清華大學,曾工作于大疆,宜信大數據創新中心,Tencent和友盟。歡迎關注,多多交流多多指教????

    ?

    推薦閱讀

    • 手把手教你配置VS Code 遠程開發工具,工作效率提升N倍

    • 用大白話徹底搞懂 HBase RowKey 詳細設計

    • 后端程序員必備:書寫高質量SQL的30條建議

    • Go 遠超 Python,機器學習人才極度稀缺,全球 16,655 位程序員告訴你這些真相!

    • 任正非談“狼文化”:華為沒有 996,更沒有 007

    • 區塊鏈必讀“上鏈”哲學:“胖鏈下”與“瘦鏈上”

    • 在商業中,如何與人工智能建立共生關系?

    真香,朕在看了!

    總結

    以上是生活随笔為你收集整理的震惊!阿里的程序员竟被一个简单的 SQL 查询难住了!的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 国产小视频在线观看免费 | 成人免费观看网站 | 精品人妻无码中文字幕18禁 | 久久久久人妻一区二区三区 | www在线视频| 快播在线视频 | 午夜激情啪啪 | 人人干美女 | 成人自拍网站 | 久久91亚洲精品中文字幕奶水 | 1000亚洲裸体人体 | 亚洲区 欧美区 | 欧美日韩在线视频一区 | 蜜桃精品在线 | 亚洲a v网站 | 福利一区福利二区 | 日本打白嫩屁股视频 | 一级aaa毛片 | 精品无码一区二区三区爱欲 | 麻豆一区二区99久久久久 | 色狠狠综合网 | 日韩人妻一区二区三区蜜桃视频 | 色婷婷综合久久久久中文 | 国产激情在线观看 | 国产精品二三区 | 最新日韩中文字幕 | 欧美日韩在线网站 | 免费观看黄色网页 | 欧美日韩久久久久久 | 樱花电影最新免费观看国语版 | av在线免 | 一级特级毛片 | 男女黄床上色视频免费的软件 | 国产精品久久久一区二区 | 成色网 | 久久嫩草精品久久久久 | 久久综合综合久久 | 亚洲性事 | 婷婷丁香六月天 | 亚欧乱色 | 免费爱爱网址 | 日本高清久久 | 香蕉久草 | 五月天堂婷婷 | 国产精品一区二区在线免费观看 | 国产做a| 国产偷自拍视频 | 国产在线视频卡一卡二 | 日本污污网站 | 日本老太婆做爰视频 | 偷拍一区二区 | 国产精品成人免费一区久久羞羞 | 免费激情视频网站 | 亚洲av永久无码精品一区二区国产 | 日韩成人午夜 | 91久久在线| 国产麻豆一区二区三区 | 在线日本视频 | 伊人网五月天 | 男人操女人逼逼视频 | 国产午夜精品福利 | 中文字幕av一区二区三区人妻少妇 | 高h av| 欧美日韩一区二区久久 | 天堂аⅴ在线最新版在线 | 精品国产美女 | 美女一二区 | 野花视频在线免费观看 | 成人福利在线 | 日韩午夜免费视频 | 国产亚洲欧美日韩精品一区二区三区 | 成人性生交大片 | 一区二区在线视频免费观看 | 成人区人妻精品一区 | 国产偷自拍 | 自拍视频网站 | 人妻体体内射精一区二区 | 黄色图片小说 | 白白色免费视频 | 欧美一级在线播放 | 精品福利三区3d卡通动漫 | 精品少妇无码av无码专区 | 91直接进入 | 国产只有精品 | 国产精品白嫩极品美女视频 | 欧美男女啪啪 | 一级黄色欧美 | 91在线观看免费高清完整版在线观看 | 男女互插视频 | 国产精品网友自拍 | 91视频com| 国产精品18久久久久久vr下载 | a视频在线免费观看 | 男人av影院 | 看特级毛片 | 日韩经典三级 | 一本大道久久久久精品嫩草 | 亚洲国产999 | www.夜夜爽 |