精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

SQL為什么不可能跑得快

jf_ro2CN3Fa ? 來源:github.com ? 2024-01-24 09:41 ? 次閱讀

我們討論過代碼編寫的難和繁的原理問題,現在關注性能問題,運行速度當然是非常重要的事情。

我們知道,軟件不能改變硬件的性能,CPU 和硬盤該多快就多快。不過,我們可以設計出低復雜度的算法,也就是計算量更小的算法,計算機執行的動作變少,自然也就會快了。本來要做 1 億次運算,如果有個好算法能把計算量降低到 100 萬次,那快出 100 倍就不奇怪了。但是,光想出算法還不夠,還要把這個算法實實在在地用某種程序語言寫出來,否則計算機不會執行。

然而,如果采用的程序語言不給力,就有可能真地寫不出來,這時候就干瞪眼忍受低速度。

SQL 就會經常發生這種事。我們用這個簡單例子來說明:從 1 億條數據中取出前 10 名,用 SQL 寫出來并不復雜:

SELECT TOP 10 * FROM Orders ORDER BY Amount DESC

這個語句里有個 ORDER BY 的字樣,對應的執行邏輯就是要對 1 億條數據做大排序。我們知道,排序是個非常慢的動作,要把數據遍歷多次(具體復雜度是 N*logN 次 ),如果數據量大到內存裝不下,那還需要外存做緩存,性能還會急劇下降。如果嚴格按這句 SQL 描述的邏輯去執行,這個運算無論如何是跑不快的。

其實,我們知道,只是取前 10 名并不需要將所有數據做大排序,只要在遍歷時始終保持一個前 10 名的小集合,遍歷過程中不斷地修正這個小集合,一次遍歷可以了,復雜度是 N*log10,和 log1億相比差了 8 倍左右,也就是計算量能小 8 倍,而且這種算法完全不需要外存做緩存。

遺憾的是,用 SQL 無法描述這樣的計算過程,只能寫成上面那個樣子,然后指望數據庫去優化。所幸,幾乎所有數據庫都會優化這個句子,沒有傻到去做大排序了,所以也能跑得比較快。

但是,情況再復雜一些會怎樣呢?比如我們把需求改成計算分組內的前 10 名,SQL 寫出來是這樣的:

SELECT * FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Area ORDER BY Amount DESC) rn
    FROM Orders )
 WHERE rn<=10

這和剛才針對全集取前 10 名的寫法相差就很大了,這是我們之前說的缺失離散性導致的。要先借助窗口函數造一個組內序號出來,再用子查詢過濾出符合條件的記錄,也就是有點“繞”了。

無論如何,這里還是有 ORDER BY 字樣,其中的運算邏輯還是要排序。我們實際測試發現,在 Oracle 中,同樣的數據量,計算這種分組前 10 名要比上面那個全集前 10 名慢出幾十倍,按說多個分組應該只慢一點點才對。Oracle 有很大可能性真地去做了排序甚至是外存排序(當然我們沒讀過 Oracle 的源代碼并不能確定),數據庫優化引擎在這種稍復雜的情況下就暈掉了,只能老老實實按 SQL 寫的邏輯去執行,性能就會陡降。

當然,也許哪天數據庫又進化了,碰到這種情況也會優化了(事實上確實有了)。但總有更復雜的情況,而數據庫優化引擎的進化速度是非常慢的。

比如這么一個更復雜的需求,做電商系統中的漏斗分析,計算每一步動作后的用戶流失率。下面是一個實際業務中發生的三步漏斗計算,SQL 會寫成這樣:

WITH e1 AS (
    SELECT userid, visittime AS step1_time, MIN(sessionid) AS sessionid, 1 AS step1
    FROM defined_events e1 JOIN eventgroup ON eventgroup.id = e1.eventgroup
    WHERE visittime >= DATE_ADD(arg_date,INTERVAL -14 day) AND visittime < arg_date AND eventgroup.name='SiteVisit'
    GROUP BY userid,visittime
), e2 AS (
    SELECT e2.userid, MIN(e2.sessionid) AS sessionid, 1 AS step2, MIN(visittime) AS step2_time, MIN(e1.step1_time) AS step1_time
    FROM defined_events e2 JOIN e1 ON e1.sessionid = e2.sessionid AND visittime > step1_time JOIN eventgroup ON eventgroup.id = e2.eventgroup
    WHERE visittime < DATE_ADD(step1_time ,INTERVAL +1 day) AND eventgroup.name = 'ProductDetailPage'
    GROUP BY e2.userid
), e3 AS (
    SELECT e3.userid, MIN(e3.sessionid) AS sessionid, 1 AS step3, MIN(visittime) AS step3_time, MIN(e2.step1_time) AS step1_time
    FROM defined_events e3 JOIN e2 ON e2.sessionid = e3.sessionid AND visittime > step2_time
    JOIN eventgroup ON eventgroup.id = e3.eventgroup
    WHERE visittime < DATE_ADD(step1_time ,INTERVAL +1 day) AND (eventgroup.name = 'OrderConfirmationType1')
    GROUP BY  e3.userid
)
SELECT s.devicetype AS devicetype,
    COUNT(DISTINCT CASE WHEN funnel_conversions.step1 IS NOT NULL THEN funnel_conversions.step1_userid  ELSE NULL END) AS step1_count,
    COUNT(DISTINCT CASE WHEN funnel_conversions.step2 IS NOT NULL THEN funnel_conversions.step2_userid  ELSE NULL END) AS step2_count,
    COUNT(DISTINCT CASE WHEN funnel_conversions.step3 IS NOT NULL THEN funnel_conversions.step3_userid  ELSE NULL END) AS step3_count,
    COUNT(DISTINCT CASE WHEN funnel_conversions.step3 IS NOT NULL THEN funnel_conversions.step3_userid  ELSE NULL END) 
    / COUNT(DISTINCT CASE WHEN funnel_conversions.step1 IS NOT NULL THEN funnel_conversions.step1_userid  ELSE NULL END) AS step3_rate
FROM (
    SELECT e1.step1_time AS step1_time, e1.userid AS userid, e1.userid AS step1_userid, e2.userid AS step2_userid,e3.userid AS step3_userid,
           e1.sessionid AS step1_sessionid, step1, step2, tep3
    FROM e1 LEFT JOIN e2 ON e1.userid=e2.userid LEFT JOIN e3 ON e2.userid=e3.userid ) funnel_conversions
LEFT JOIN sessions s ON funnel_conversions.step1_sessionid = s.id 
GROUP BY s.devicetype

這個 SQL“繞”得很嚴重了,看懂非常費勁,擺在這里就是感受一下。這還只是三步,想再多算幾步還得寫更多子查詢,那就擺不出來了。這種復雜的 SQL,真想不出這能怎么做優化。結果,這句 SQL 在 Snwoflake 的 Medium 集群上(4 節點)跑了 3 分鐘沒出來,用戶只能放棄。

所以,不能也不要指望數據庫優化,還是要自己寫出高性能算法出來。

那么,什么樣的程序語言才能寫出剛才說的這些算法呢?

很多,C++Java 這些都可以。理論上用 SQL 寫的存儲過程也可以,但工程實現的結果還是會太慢,這還是因為缺失離散性。比如 TopN 問題,在 SQL 中要保存那 10 個成員的小集合也得用臨時表,很難寫也很慢。

那就不用 SQL,用 C++,Java 這些去寫好了。

這又回到我們之前說的集合化特性了,這些語言缺乏集合化,寫出來很繁瑣。像分組 TopN,如果要考慮各種數據類型、多個分組鍵、還可能帶著計算式,幾千行也未必寫得出來。而漏斗分析這種復雜運算,還要考慮大數據存儲問題,寫個幾萬行也很正常。開發成本極高,以后維護時也累死人。

這樣,在現實中就沒有可操作性了。

所以,代碼能寫著簡單就變得非常有意義了。一方面是短小,這意味著工作量少,另一方面還要容易,這意味著更多的程序員可以寫。從這個角度上看,寫著簡單和跑得快是一回事。想跑得快,就是要有一種程序語言能讓高性能算法寫著簡單,這才有可操作性。

這樣的標準,可能只有 esProc SPL 適合了,它同時擁有集合化和離散性兩種特性,又提供相當多固有的高性能算法庫函數,這才能寫著簡單,從而跑得快。

前面的前 10 名問題用 SPL 寫出來是這樣的:

Orders.groups(;top(10;-Amount)
Orders.groups(Area;top(10;-Amount))


SPL 把 TopN 理解為聚合計算,這個語句中沒有排序的字樣,也就不會做大排序,而采用剛才說的快速算法了。而且,這里分組前 10 名和全集前 10 名的寫法基本一樣,只是多了分組鍵。這也是在集合化的基礎上支持了離散性的結果。

漏斗分析用 SPL 寫出來是這樣:

A
1 =now()
2 =eventgroup=file("eventgroup.btx").import@b()
3 =devicetype=file("devicetype.btx").import@b()
4 =long(elapse(arg_date,-14))
5 =long(arg_date)
6 =long(arg_date+1)
7 =A2.(case(NAME,"SiteVisit":1,"ProductDetailPage":2,"OrderConfirmationType1":3;null))
8 =file("defined_events.ctx").open()
9 =A8.cursor@m(USERID,SESSIONID,VISITTIME,EVENTGROUPNO;VISITTIME>=A4 && VISITTIME
10 =sessions=file("sessions.ctx").open().cursor@m(USERID,ID,DEVICETYPENO;;A9)
11 =A9.joinx@m(USERID:SESSIONID,A10ID,DEVICETYPENO)
12 =A11.group(USERID)
13 =A12.new(~.align@a(3,EVENTGROUPNO):e,e(1).select(VISITTIME
14 =A13.run(e=join@m(e1:e1,SESSIONID;e2:e2,SESSIONID).select(e2=e2.select(VISITTIME>e1.VISITTIME && VISITTIME
15 =A14.run(e0=e1.id(DEVICETYPENO),e1=e.min(e1.VISITTIME),e2=e.min(e2),e=e.min(e1.SESSIONID),e3=e3.select(SESSIONID==e && VISITTIME>e2 && VISITTIME
16 =A15.news(e;~:DEVICETYPE,e2,e3)
17 =A16.groups(DEVICETYPE;count(1):STEP1_COUNT,count(e2):STEP2_COUNT,count(e3):STEP3_COUNT,null:STEP3_RATE)
18 =A17.run(DEVICETYPE=devicetype.m(DEVICETYPE).DEVICETYPE,STEP3_RATE=STEP3_COUNT/STEP1_COUNT)
19 =interval@s(A1,now())

這個代碼要比前面的 SQL 更短,而且更靈活,再增加幾步也還是這段代碼。實測的結果,這段代碼用單臺服務器 10 秒就跑完了。 有了集合化和離散性的 SPL,才能做到寫著簡單又跑得快。


本文來源
github.com

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10825

    瀏覽量

    211151
  • 計算機
    +關注

    關注

    19

    文章

    7421

    瀏覽量

    87718
  • SQL
    SQL
    +關注

    關注

    1

    文章

    760

    瀏覽量

    44076
  • 程序
    +關注

    關注

    116

    文章

    3777

    瀏覽量

    80851

原文標題:寫著簡單和跑得快是一回事,SQL 為什么不可能跑得快?

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    反轉“不可能”,硬件創新以你為中心

    回到“大眾創業,萬眾創新”風口下的智能硬件創業也是如此,從最初的idea到demo,從路演到資金成功注入,從起初供應鏈搭建直至完善,太多的“不可能”到“可能”,2015中國硬件創新大賽陪你一起見證。
    發表于 09-22 11:48 ?1277次閱讀

    深井中的深度學習:MCU+AI,讓“不可能”的田園機井智能抄表成為可能

    深井中的深度學習:MCU+AI,讓“不可能”的田園機井智能抄表成為可能
    的頭像 發表于 09-21 17:41 ?777次閱讀
    深井中的深度學習:MCU+AI,讓“<b class='flag-5'>不可能</b>”的田園機井智能抄表成為<b class='flag-5'>可能</b>!

    STM32小系統實現wifi無線通訊程序怎么才能跑得起來

    等大神幫助,做了個STM32小系統,主要實現wifi無線通訊,使用的是鋰電池供電,但目前問題是設備端必須要有一根線與jlink共地(jlink與電腦相連 )程序才能跑得起來,不然就無法執行進去,網上說的要拔排線試過了(不起作用),求大家幫助
    發表于 05-08 06:35

    如何讓不可能成為可能

    我們應當張開雙臂擁抱快節奏的技術變革,它推動科學技術的進步,讓人們更加緊密相連并感到安全自信,它改變了我們此前認為的不可能。這些成果的影響不再只孤立于一個狹窄的垂直市場,它滲透進了各行各業,對現有
    發表于 10-15 06:12

    如果個人去流片的話可不可能啊?

    如果個人去流片的話可不可能啊?自己設計一個芯片去流片,可能嗎?
    發表于 06-18 06:30

    錘子新機不可能是T3!應是堅果2或新系列

      春天了,老羅之前說過在春天會發布一款新機,所以網上就爆出了許多關于新機的消息,但是有很多消息說即將發布的新機是傳聞已久的T3,這個是不可能的,春天要不發布的機器根本不可能是T3。
    發表于 03-16 10:10 ?2890次閱讀

    什么是區塊鏈不可能三角為什么不可突破

    CAP定理證明了:當網絡存在分區時,提供可靠的原子一致性數據是不可能的,但是想要實現一致性、可用性、分區容錯性,三個屬性中的兩個是可行的。在異步通信系統中,當沒有鎖提供時,如果出現消息丟失,即使允許過時的數據返回,提供一致性數據也是不可能的。在同步通信系統中,可以在一致性
    發表于 02-26 11:03 ?3180次閱讀
    什么是區塊鏈<b class='flag-5'>不可能</b>三角為什么<b class='flag-5'>不可</b>突破

    自動駕駛車上路需智能路網配套

    路好,車才能跑得快
    的頭像 發表于 05-14 11:31 ?2182次閱讀

    決戰智能家居領域 三類選手并行

    短短幾年間,萬億智能家居新賽道上,聚集來自全球的眾多參賽者。除了亞馬遜、谷歌、BAT等互聯網企業,華為等IT芯片企業,小米等手機企業,還有海爾等轉型中的家電企業,以及眾多主打智能單品的初創企業。那么,在這場全球化的巨頭戰役中,誰既能跑得快跑得穩,還
    發表于 05-22 10:57 ?417次閱讀

    天下AI,唯不破!

    跑得快誰搶得市場的機會就越大。
    的頭像 發表于 06-10 09:29 ?3254次閱讀

    馬云與馬斯克上演了一出雞同鴨講式的“雙馬尬聊”

    “和計算機下棋這很愚蠢,像100年前人們創造了機器,人們說我可以比汽車跑得快這是不可能的,只有傻子才會去和汽車賽跑……我們要做我們擅長的事情。”
    的頭像 發表于 09-03 14:49 ?4718次閱讀

    什么是區塊鏈中的不可能三角

    區塊鏈本質上是一個去中心化的分布式賬本數據庫,它也存在“不可能三角”。今天,我們就來講講“不可能三角”在區塊鏈世界是如何權衡和妥協的。
    發表于 12-13 08:59 ?8472次閱讀

    區塊鏈如何解決醫療數據中的不可能三角

    不可能三角”一詞,最早來自金融經濟領域,指的是資本自由流動、匯率穩定和貨幣政策獨立性三者不可能兼得。
    發表于 01-17 10:26 ?1590次閱讀

    超輕量分組密碼算法GRANULE的不可能差分分析

    GRANULE算法是一個超輕量分組密碼算法,有著較好的軟硬件實現性能,但目前尚沒有該算法在不可能差分分析下的安全性評估結果。為此,利用中間相錯技術,找到 GRANULE64算法多條5輪不可能差分區
    發表于 06-01 14:27 ?3次下載

    英飛凌主驅逆變器助力電動汽車跑得快跑得

    電動汽車越來越受歡迎。如今電動汽車的發展趨勢是,電機功率越來越大,但為了保證續航里程,行駛中的電耗也要越來越低。這看似不可能完成的任務,背后的最大功臣正是主驅逆變器。
    的頭像 發表于 04-05 13:46 ?497次閱讀
    英飛凌主驅逆變器助力電動汽車<b class='flag-5'>跑得快跑得</b>遠