色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

SQL為什么不可能跑得快

jf_ro2CN3Fa ? 來(lái)源:github.com ? 2024-01-24 09:41 ? 次閱讀

我們討論過(guò)代碼編寫(xiě)的難和繁的原理問(wèn)題,現(xiàn)在關(guān)注性能問(wèn)題,運(yùn)行速度當(dāng)然是非常重要的事情。

我們知道,軟件不能改變硬件的性能,CPU 和硬盤(pán)該多快就多快。不過(guò),我們可以設(shè)計(jì)出低復(fù)雜度的算法,也就是計(jì)算量更小的算法,計(jì)算機(jī)執(zhí)行的動(dòng)作變少,自然也就會(huì)快了。本來(lái)要做 1 億次運(yùn)算,如果有個(gè)好算法能把計(jì)算量降低到 100 萬(wàn)次,那快出 100 倍就不奇怪了。但是,光想出算法還不夠,還要把這個(gè)算法實(shí)實(shí)在在地用某種程序語(yǔ)言寫(xiě)出來(lái),否則計(jì)算機(jī)不會(huì)執(zhí)行。

然而,如果采用的程序語(yǔ)言不給力,就有可能真地寫(xiě)不出來(lái),這時(shí)候就干瞪眼忍受低速度。

SQL 就會(huì)經(jīng)常發(fā)生這種事。我們用這個(gè)簡(jiǎn)單例子來(lái)說(shuō)明:從 1 億條數(shù)據(jù)中取出前 10 名,用 SQL 寫(xiě)出來(lái)并不復(fù)雜:

SELECT TOP 10 * FROM Orders ORDER BY Amount DESC

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

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

遺憾的是,用 SQL 無(wú)法描述這樣的計(jì)算過(guò)程,只能寫(xiě)成上面那個(gè)樣子,然后指望數(shù)據(jù)庫(kù)去優(yōu)化。所幸,幾乎所有數(shù)據(jù)庫(kù)都會(huì)優(yōu)化這個(gè)句子,沒(méi)有傻到去做大排序了,所以也能跑得比較快。

但是,情況再?gòu)?fù)雜一些會(huì)怎樣呢?比如我們把需求改成計(jì)算分組內(nèi)的前 10 名,SQL 寫(xiě)出來(lái)是這樣的:

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

這和剛才針對(duì)全集取前 10 名的寫(xiě)法相差就很大了,這是我們之前說(shuō)的缺失離散性導(dǎo)致的。要先借助窗口函數(shù)造一個(gè)組內(nèi)序號(hào)出來(lái),再用子查詢(xún)過(guò)濾出符合條件的記錄,也就是有點(diǎn)“繞”了。

無(wú)論如何,這里還是有 ORDER BY 字樣,其中的運(yùn)算邏輯還是要排序。我們實(shí)際測(cè)試發(fā)現(xiàn),在 Oracle 中,同樣的數(shù)據(jù)量,計(jì)算這種分組前 10 名要比上面那個(gè)全集前 10 名慢出幾十倍,按說(shuō)多個(gè)分組應(yīng)該只慢一點(diǎn)點(diǎn)才對(duì)。Oracle 有很大可能性真地去做了排序甚至是外存排序(當(dāng)然我們沒(méi)讀過(guò) Oracle 的源代碼并不能確定),數(shù)據(jù)庫(kù)優(yōu)化引擎在這種稍復(fù)雜的情況下就暈掉了,只能老老實(shí)實(shí)按 SQL 寫(xiě)的邏輯去執(zhí)行,性能就會(huì)陡降。

當(dāng)然,也許哪天數(shù)據(jù)庫(kù)又進(jìn)化了,碰到這種情況也會(huì)優(yōu)化了(事實(shí)上確實(shí)有了)。但總有更復(fù)雜的情況,而數(shù)據(jù)庫(kù)優(yōu)化引擎的進(jìn)化速度是非常慢的。

比如這么一個(gè)更復(fù)雜的需求,做電商系統(tǒng)中的漏斗分析,計(jì)算每一步動(dòng)作后的用戶(hù)流失率。下面是一個(gè)實(shí)際業(yè)務(wù)中發(fā)生的三步漏斗計(jì)算,SQL 會(huì)寫(xiě)成這樣:

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

這個(gè) SQL“繞”得很?chē)?yán)重了,看懂非常費(fèi)勁,擺在這里就是感受一下。這還只是三步,想再多算幾步還得寫(xiě)更多子查詢(xún),那就擺不出來(lái)了。這種復(fù)雜的 SQL,真想不出這能怎么做優(yōu)化。結(jié)果,這句 SQL 在 Snwoflake 的 Medium 集群上(4 節(jié)點(diǎn))跑了 3 分鐘沒(méi)出來(lái),用戶(hù)只能放棄。

所以,不能也不要指望數(shù)據(jù)庫(kù)優(yōu)化,還是要自己寫(xiě)出高性能算法出來(lái)。

那么,什么樣的程序語(yǔ)言才能寫(xiě)出剛才說(shuō)的這些算法呢?

很多,C++Java 這些都可以。理論上用 SQL 寫(xiě)的存儲(chǔ)過(guò)程也可以,但工程實(shí)現(xiàn)的結(jié)果還是會(huì)太慢,這還是因?yàn)槿笔щx散性。比如 TopN 問(wèn)題,在 SQL 中要保存那 10 個(gè)成員的小集合也得用臨時(shí)表,很難寫(xiě)也很慢。

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

這又回到我們之前說(shuō)的集合化特性了,這些語(yǔ)言缺乏集合化,寫(xiě)出來(lái)很繁瑣。像分組 TopN,如果要考慮各種數(shù)據(jù)類(lèi)型、多個(gè)分組鍵、還可能帶著計(jì)算式,幾千行也未必寫(xiě)得出來(lái)。而漏斗分析這種復(fù)雜運(yùn)算,還要考慮大數(shù)據(jù)存儲(chǔ)問(wèn)題,寫(xiě)個(gè)幾萬(wàn)行也很正常。開(kāi)發(fā)成本極高,以后維護(hù)時(shí)也累死人。

這樣,在現(xiàn)實(shí)中就沒(méi)有可操作性了。

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

這樣的標(biāo)準(zhǔn),可能只有 esProc SPL 適合了,它同時(shí)擁有集合化和離散性?xún)煞N特性,又提供相當(dāng)多固有的高性能算法庫(kù)函數(shù),這才能寫(xiě)著簡(jiǎn)單,從而跑得快。

前面的前 10 名問(wèn)題用 SPL 寫(xiě)出來(lái)是這樣的:

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


SPL 把 TopN 理解為聚合計(jì)算,這個(gè)語(yǔ)句中沒(méi)有排序的字樣,也就不會(huì)做大排序,而采用剛才說(shuō)的快速算法了。而且,這里分組前 10 名和全集前 10 名的寫(xiě)法基本一樣,只是多了分組鍵。這也是在集合化的基礎(chǔ)上支持了離散性的結(jié)果。

漏斗分析用 SPL 寫(xiě)出來(lái)是這樣:

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())

這個(gè)代碼要比前面的 SQL 更短,而且更靈活,再增加幾步也還是這段代碼。實(shí)測(cè)的結(jié)果,這段代碼用單臺(tái)服務(wù)器 10 秒就跑完了。 有了集合化和離散性的 SPL,才能做到寫(xiě)著簡(jiǎn)單又跑得快。


本文來(lái)源
github.com

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10855

    瀏覽量

    211605
  • 計(jì)算機(jī)
    +關(guān)注

    關(guān)注

    19

    文章

    7489

    瀏覽量

    87872
  • SQL
    SQL
    +關(guān)注

    關(guān)注

    1

    文章

    762

    瀏覽量

    44117
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3785

    瀏覽量

    81008

原文標(biāo)題:寫(xiě)著簡(jiǎn)單和跑得快是一回事,SQL 為什么不可能跑得快?

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    反轉(zhuǎn)“不可能”,硬件創(chuàng)新以你為中心

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

    深井中的深度學(xué)習(xí):MCU+AI,讓“不可能”的田園機(jī)井智能抄表成為可能

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

    STM32小系統(tǒng)實(shí)現(xiàn)wifi無(wú)線(xiàn)通訊程序怎么才能跑得起來(lái)

    等大神幫助,做了個(gè)STM32小系統(tǒng),主要實(shí)現(xiàn)wifi無(wú)線(xiàn)通訊,使用的是鋰電池供電,但目前問(wèn)題是設(shè)備端必須要有一根線(xiàn)與jlink共地(jlink與電腦相連 )程序才能跑得起來(lái),不然就無(wú)法執(zhí)行進(jìn)去,網(wǎng)上說(shuō)的要拔排線(xiàn)試過(guò)了(不起作用),求大家?guī)椭?/div>
    發(fā)表于 05-08 06:35

    如何讓不可能成為可能

    我們應(yīng)當(dāng)張開(kāi)雙臂擁抱快節(jié)奏的技術(shù)變革,它推動(dòng)科學(xué)技術(shù)的進(jìn)步,讓人們更加緊密相連并感到安全自信,它改變了我們此前認(rèn)為的不可能。這些成果的影響不再只孤立于一個(gè)狹窄的垂直市場(chǎng),它滲透進(jìn)了各行各業(yè),對(duì)現(xiàn)有
    發(fā)表于 10-15 06:12

    如果個(gè)人去流片的話(huà)可不可能啊?

    如果個(gè)人去流片的話(huà)可不可能啊?自己設(shè)計(jì)一個(gè)芯片去流片,可能嗎?
    發(fā)表于 06-18 06:30

    錘子新機(jī)不可能是T3!應(yīng)是堅(jiān)果2或新系列

      春天了,老羅之前說(shuō)過(guò)在春天會(huì)發(fā)布一款新機(jī),所以網(wǎng)上就爆出了許多關(guān)于新機(jī)的消息,但是有很多消息說(shuō)即將發(fā)布的新機(jī)是傳聞已久的T3,這個(gè)是不可能的,春天要不發(fā)布的機(jī)器根本不可能是T3。
    發(fā)表于 03-16 10:10 ?2896次閱讀

    什么是區(qū)塊鏈不可能三角為什么不可突破

    CAP定理證明了:當(dāng)網(wǎng)絡(luò)存在分區(qū)時(shí),提供可靠的原子一致性數(shù)據(jù)是不可能的,但是想要實(shí)現(xiàn)一致性、可用性、分區(qū)容錯(cuò)性,三個(gè)屬性中的兩個(gè)是可行的。在異步通信系統(tǒng)中,當(dāng)沒(méi)有鎖提供時(shí),如果出現(xiàn)消息丟失,即使允許過(guò)時(shí)的數(shù)據(jù)返回,提供一致性數(shù)據(jù)也是不可能的。在同步通信系統(tǒng)中,可以在一致性
    發(fā)表于 02-26 11:03 ?3209次閱讀
    什么是區(qū)塊鏈<b class='flag-5'>不可能</b>三角為什么<b class='flag-5'>不可</b>突破

    自動(dòng)駕駛車(chē)上路需智能路網(wǎng)配套

    路好,車(chē)才能跑得快
    的頭像 發(fā)表于 05-14 11:31 ?2198次閱讀

    決戰(zhàn)智能家居領(lǐng)域 三類(lèi)選手并行

    短短幾年間,萬(wàn)億智能家居新賽道上,聚集來(lái)自全球的眾多參賽者。除了亞馬遜、谷歌、BAT等互聯(lián)網(wǎng)企業(yè),華為等IT芯片企業(yè),小米等手機(jī)企業(yè),還有海爾等轉(zhuǎn)型中的家電企業(yè),以及眾多主打智能單品的初創(chuàng)企業(yè)。那么,在這場(chǎng)全球化的巨頭戰(zhàn)役中,誰(shuí)既能跑得快跑得穩(wěn),還
    發(fā)表于 05-22 10:57 ?422次閱讀

    天下AI,唯不破!

    誰(shuí)跑得快誰(shuí)搶得市場(chǎng)的機(jī)會(huì)就越大。
    的頭像 發(fā)表于 06-10 09:29 ?3264次閱讀

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

    “和計(jì)算機(jī)下棋這很愚蠢,像100年前人們創(chuàng)造了機(jī)器,人們說(shuō)我可以比汽車(chē)跑得快這是不可能的,只有傻子才會(huì)去和汽車(chē)賽跑……我們要做我們擅長(zhǎng)的事情。”
    的頭像 發(fā)表于 09-03 14:49 ?4783次閱讀

    什么是區(qū)塊鏈中的不可能三角

    區(qū)塊鏈本質(zhì)上是一個(gè)去中心化的分布式賬本數(shù)據(jù)庫(kù),它也存在“不可能三角”。今天,我們就來(lái)講講“不可能三角”在區(qū)塊鏈?zhǔn)澜缡侨绾螜?quán)衡和妥協(xié)的。
    發(fā)表于 12-13 08:59 ?8509次閱讀

    區(qū)塊鏈如何解決醫(yī)療數(shù)據(jù)中的不可能三角

    不可能三角”一詞,最早來(lái)自金融經(jīng)濟(jì)領(lǐng)域,指的是資本自由流動(dòng)、匯率穩(wěn)定和貨幣政策獨(dú)立性三者不可能兼得。
    發(fā)表于 01-17 10:26 ?1610次閱讀

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

    GRANULE算法是一個(gè)超輕量分組密碼算法,有著較好的軟硬件實(shí)現(xiàn)性能,但目前尚沒(méi)有該算法在不可能差分分析下的安全性評(píng)估結(jié)果。為此,利用中間相錯(cuò)技術(shù),找到 GRANULE64算法多條5輪不可能差分區(qū)
    發(fā)表于 06-01 14:27 ?3次下載

    英飛凌主驅(qū)逆變器助力電動(dòng)汽車(chē)跑得快跑得遠(yuǎn)

    電動(dòng)汽車(chē)越來(lái)越受歡迎。如今電動(dòng)汽車(chē)的發(fā)展趨勢(shì)是,電機(jī)功率越來(lái)越大,但為了保證續(xù)航里程,行駛中的電耗也要越來(lái)越低。這看似不可能完成的任務(wù),背后的最大功臣正是主驅(qū)逆變器。
    的頭像 發(fā)表于 04-05 13:46 ?543次閱讀
    英飛凌主驅(qū)逆變器助力電動(dòng)汽車(chē)<b class='flag-5'>跑得快跑得</b>遠(yuǎn)
    主站蜘蛛池模板: 忘忧草研究所 麻豆| 强开乳罩摸双乳吃奶视频| 色噜噜噜亚洲男人的天堂| 一起碰一起噜一起草视频| 动漫美女被到爽了流| 美国兽皇zoo在线播放 | 睡觉被偷偷进入magnet| 69精品国产人妻蜜桃国产毛片| 国产久久亚洲美女久久| 欧美男同gay粗大又长| 伊人久久青草青青综合| 国产精品国产三级国产AV麻豆| 欧美z000z猪| 在线观看免费国产成人软件| 国产在线精品亚洲观看不卡欧美| 日本性xxx| 99国产精品久久人妻| 久久婷婷电影网| 亚洲高清在线视频| 国产东北男同志videos网站| 秋秋影视午夜福利高清| 97色香蕉在线| 老阿姨才是最有V味的直播| 亚洲午夜AV久久久精品影院色戒| 国产精品亚欧美一区二区三区 | 神马伦理不卡午夜电影| h片下载地址| 美女伸开两腿让我爽| 在线观看免费精品国产| 狠狠色在在线视频观看| 鸭子玩富婆流白浆视频| 国产精品俺来也在线观看| 青青久在线| 扒开老师大腿猛进AAA片| 嗯啊不要老师| 91精品一区二区综合在线| 久久久无码精品亚洲日韩按摩| 一级毛片西西人体44rt高清| 黄色直接观看| 亚洲幼女网| 久久久久婷婷国产综合青草|