亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

在MySQL中實(shí)現(xiàn)二分查找的詳細(xì)教程

 更新時(shí)間:2015年05月30日 11:44:30   投稿:goldensun  
這篇文章主要介紹了在MySQL中實(shí)現(xiàn)二分查找的詳細(xì)教程,來自計(jì)算機(jī)研究生考試原題,需要的朋友可以參考下

給定一個(gè)升序排列的自然數(shù)數(shù)組,數(shù)組中包含重復(fù)數(shù)字,例如:[1,2,2,3,4,4,4,5,6,7,7]。問題:給定任意自然數(shù),對(duì)數(shù)組進(jìn)行二分查找,返回?cái)?shù)組正確的位置,給出函數(shù)實(shí)現(xiàn)。注:連續(xù)相同的數(shù)字,返回第一個(gè)匹配位置還是最后一個(gè)匹配位置,由函數(shù)傳入?yún)?shù)決定。

我為什么會(huì)出這道題目?

    二分查找在數(shù)據(jù)庫(kù)內(nèi)核實(shí)現(xiàn)中非常重要

    在數(shù)據(jù)庫(kù)的內(nèi)核實(shí)現(xiàn)中,二分查找是一個(gè)非常重要的邏輯,幾乎99%以上的SQL語句(所有索引上的范圍掃描/等值查詢/Unique查詢等),都會(huì)使用到二分查找進(jìn)行數(shù)據(jù)的定位。

    考慮一個(gè)數(shù)據(jù)庫(kù)表t1(a int primary key, b int),表上的b字段有一個(gè)B+樹索引,表中記錄的b字段取值,就是題目中的[1,2,2,3,4,4,4,5,6,7,7]序列。此時(shí),給定以下的兩條查詢語句,就是使用到了不同的二分查找邏輯:

    SQL1:  

 select * from t1 where b > 4;

    SQL2: 

select * from t1 where b >= 4;

    針對(duì)SQL1,索引的二分查找,就需要跳過所有的4,從最后一個(gè)4之后開始返回所有記錄;針對(duì)SQL2,二分查找就需要定位到第一個(gè)4,然后順序讀取所有記錄。

    除此之外,針對(duì)數(shù)據(jù)庫(kù)中其他的查詢邏輯,二分查找還需要附帶更多的功能,例如:

    SQL3: 

select * from t1 where b < 2;

    SQL4:

 select * from t1 where b <= 2;

    由于數(shù)據(jù)庫(kù)索引同時(shí)支持反向掃描,因此SQL3、SQL4的語句,都可以使用索引反向掃描。反向掃描時(shí),SQL3需要定位到索引中的第一個(gè)2;而SQL4,則需要定位到索引的最后一個(gè)2,然后開始反向返回滿足查詢條件的索引記錄。
    二分查找在程序設(shè)計(jì)中,是一個(gè)十分基礎(chǔ)并且易錯(cuò)的功能

    第一個(gè)真正正確的二分查找算法,在第一個(gè)二分查找實(shí)現(xiàn)之后的12年,才被發(fā)表出來。通過Google,輸入Binary Search或者是二分查找關(guān)鍵字,有大量的相關(guān)的文章或者博客討論此話題。

二分查找實(shí)現(xiàn),需要注意的問題

本文不準(zhǔn)備詳細(xì)介紹一個(gè)正確的二分查找應(yīng)該是如何實(shí)現(xiàn)的,畢竟現(xiàn)在網(wǎng)上有著大量的正確版本。接下來,根據(jù)批改試卷過程中發(fā)現(xiàn)的一些問題,做一些簡(jiǎn)單的分析,希望對(duì)大家實(shí)現(xiàn)一個(gè)有效的二分查找算法,甚至是一個(gè)數(shù)據(jù)庫(kù)內(nèi)可用的二分查找算法,有所幫助。
問題一:是否檢查參數(shù)的有效性

大量的試卷,在給出此問題的解決算法時(shí),直接拿著low,high參數(shù)開始進(jìn)行計(jì)算,但是卻沒有檢查low/high參數(shù)。low/high是否相同,數(shù)組中是否存在記錄?low/high構(gòu)成的區(qū)間是否有效?代碼的魯棒性不足。

在數(shù)據(jù)庫(kù)的二分查找實(shí)現(xiàn)中,一般是對(duì)一個(gè)索引頁面進(jìn)行二分查找。索引頁面中有可能根本不存在用戶的記錄(索引頁面中的記錄全部被刪除,又沒有與兄弟頁面合并時(shí)),此時(shí),low/high均為0,此時(shí)如果根據(jù)low/high計(jì)算出來的mid進(jìn)行記錄的讀取,就存在邏輯錯(cuò)誤。
問題二:二分查找中值的計(jì)算

這是一個(gè)經(jīng)典的話題,如何計(jì)算二分查找中的中值?試卷中,大家一般給出了兩種計(jì)算方法:

算法一: mid = (low + high) / 2

算法二: mid = low + (high – low)/2

乍看起來,算法一簡(jiǎn)潔,算法二提取之后,跟算法一沒有什么區(qū)別。但是實(shí)際上,區(qū)別是存在的。算法一的做法,在極端情況下,(low + high)存在著溢出的風(fēng)險(xiǎn),進(jìn)而得到錯(cuò)誤的mid結(jié)果,導(dǎo)致程序錯(cuò)誤。而算法二能夠保證計(jì)算出來的mid,一定大于low,小于high,不存在溢出的問題。

回到數(shù)據(jù)庫(kù)二分查找,數(shù)據(jù)庫(kù)的一個(gè)索引頁面(大小一般是8k或者是16k),能夠存儲(chǔ)的索引記錄是有限的,因此肯定不會(huì)出現(xiàn)(low + high)溢出的風(fēng)險(xiǎn)。這也是為什么InnoDB中的中值,采用的就是算法一的實(shí)現(xiàn)。但是,作為一個(gè)嚴(yán)謹(jǐn)?shù)某绦蛟O(shè)計(jì)人員,還是推薦使用算法二,將任何潛在的風(fēng)險(xiǎn),扼殺于搖籃之中。
問題三:遞歸實(shí)現(xiàn)二分查找

超過一半的試卷,使用了遞歸調(diào)用的方式實(shí)現(xiàn)二分查找。不能說遞歸實(shí)現(xiàn)有錯(cuò),而是在于實(shí)現(xiàn)效率問題。總所周知,遞歸調(diào)用存在著壓棧/出棧的開銷,其效率是比較低下的。而以數(shù)據(jù)庫(kù)這樣一個(gè)極端優(yōu)化代碼效率,提供快速查詢響應(yīng)的系統(tǒng)來說,效率是第一位的。不建議使用遞歸方式實(shí)現(xiàn)二分查找,至少在數(shù)據(jù)庫(kù)內(nèi)核實(shí)現(xiàn)中是不允許使用的。據(jù)我所知,所有的開源數(shù)據(jù)庫(kù)系統(tǒng),例如:InnoDB,PostgreSQL都未采用遞歸方式實(shí)現(xiàn)二分查找。
問題四:如何查找第一個(gè)/最后一個(gè)等值

回到題目,要求根據(jù)傳入的參數(shù)不同,返回第一個(gè)/最后一個(gè)等值項(xiàng)。在本文的背景部分,我也解釋了此問題對(duì)應(yīng)的數(shù)據(jù)庫(kù)查詢(>,>=查詢需求是不同的)。在試卷中,超過80%的同學(xué)的答案都是先進(jìn)行二分查找,待定位到相同值之后,再根據(jù)傳入的flag(用戶需求:flag = 1,返回第一個(gè)等值項(xiàng);flag = 0,返回最后一個(gè)等值項(xiàng)),進(jìn)行順序遍歷,直至定位到滿足條件的項(xiàng)。

同樣,不能說這個(gè)實(shí)現(xiàn)是錯(cuò)的,但是也存在著性能問題。性能性能性能,永遠(yuǎn)是數(shù)據(jù)庫(kù)內(nèi)核實(shí)現(xiàn)考慮的重點(diǎn)之一(相信也是所有應(yīng)用程序的一個(gè)指標(biāo))。數(shù)據(jù)庫(kù)中,除了主鍵索引/Unique索引能夠保證鍵值唯一之外,很多二級(jí)輔助索引都是存在相同鍵值的,有時(shí)相同鍵值的項(xiàng)會(huì)超過千項(xiàng)(考慮一個(gè)用戶的訂單,或者是購(gòu)買記錄)。

假設(shè)一個(gè)索引頁面,保存著400項(xiàng)記錄,均為相同鍵值。此時(shí),使用先二分查找,后順序遍歷的算法,二分查找只能使用一次,順序遍歷199次,最終對(duì)比了200次。效率非常之低。當(dāng)然,我也欣喜的看到另外一小部分同學(xué)的做法(我期待看到的算法),用flag來糾正每次比較的最終結(jié)果。例如:比較相等(相等用0表示,大于為1,小于為-1),但是flag = 1,則返回糾正后的比較結(jié)果為1,需要移動(dòng)二分查找的high到mid,繼續(xù)二分(反之,若flag = 0,則返回糾正后的結(jié)果為-1,需要移動(dòng)二分查找的low到mid,繼續(xù)二分)。如此一來,等值仍舊可以進(jìn)行二分查找,最終的對(duì)比只需要9次,遠(yuǎn)遠(yuǎn)小于200次。

此問題,進(jìn)一步引出了下一個(gè)問題,數(shù)據(jù)庫(kù)中如何實(shí)現(xiàn)一個(gè)通用的,更為復(fù)雜的二分查找算法?
問題五:數(shù)據(jù)庫(kù)中的二分查找實(shí)現(xiàn)舉例

數(shù)據(jù)庫(kù)中的二分查找,更為復(fù)雜,需要實(shí)現(xiàn)一個(gè)通用型的二分查找算法,使用于各種不同的SQL查詢場(chǎng)景。

InnoDB針對(duì)不同的SQL語句,總結(jié)出四種不同的Search Mode,分別為:

#define    PAGE_CUR_G          1        >查詢

#define    PAGE_CUR_GE         2        >=,=查詢

#define    PAGE_CUR_L          3        <查詢

#define    PAGE_CUR_LE         4        <=查詢

然后根據(jù)這四種不同的Search Mode,在二分查找碰到相同鍵值時(shí)進(jìn)行調(diào)整。例如:若Search Mode為PAGE_CUR_G或者是PAGE_CUR_LE,則移動(dòng)low至mid,繼續(xù)進(jìn)行二分查找;若Search Mode為PAGE_CUR_GE或者是PAGE_CUR_L,則移動(dòng)high至mid,繼續(xù)進(jìn)行二分查找。

我們的TNT引擎,采用了與InnoDB不同的方案,但是也實(shí)現(xiàn)了相同的功能。TNT引擎針對(duì)相同鍵值的調(diào)整總結(jié)為下圖,在此我就不做解釋了,大家可以嘗試著自己進(jìn)行分析。

/* 操作符 includeKey     forward     compare result: 1    0        -1 */

=============================================================================

>=            1            1    |            1            -1        -1

=             1            1    |            1            -1        -1

>             0            1    |            1             1        -1

<             0            0    |            1            -1        -1

<=            1            0    |            1             1        -1

=============================================================================

相關(guān)文章

  • MySQL可重復(fù)讀級(jí)別能夠解決幻讀嗎

    MySQL可重復(fù)讀級(jí)別能夠解決幻讀嗎

    這篇文章主要給大家介紹了關(guān)于MySQL可重復(fù)讀級(jí)別能否解決幻讀的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • mysql服務(wù)1067錯(cuò)誤多種解決方案分享

    mysql服務(wù)1067錯(cuò)誤多種解決方案分享

    今天我的mysql服務(wù)器突然出來了1067錯(cuò)誤提示,無法正常啟動(dòng)了,我今天從網(wǎng)上找尋了大量的解決mysql服務(wù)1067錯(cuò)誤的辦法,有需要的朋友可以看看
    2012-03-03
  • 基于sqlalchemy對(duì)mysql實(shí)現(xiàn)增刪改查操作

    基于sqlalchemy對(duì)mysql實(shí)現(xiàn)增刪改查操作

    這篇文章主要介紹了基于sqlalchemy對(duì)mysql實(shí)現(xiàn)增刪改查操作,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 手把手教你Navicat如何導(dǎo)出Excel格式的表結(jié)構(gòu)

    手把手教你Navicat如何導(dǎo)出Excel格式的表結(jié)構(gòu)

    我們?cè)陂_發(fā)中使用數(shù)據(jù)庫(kù)時(shí)往往需要做一些備份之類的,或者需要導(dǎo)出下表結(jié)構(gòu)導(dǎo)入到其他數(shù)據(jù)庫(kù)等,下面這篇文章主要給大家介紹了關(guān)于Navicat如何導(dǎo)出Excel格式的表結(jié)構(gòu)的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • mysql中循環(huán)截取用戶信息并插入到目標(biāo)表對(duì)應(yīng)的字段中

    mysql中循環(huán)截取用戶信息并插入到目標(biāo)表對(duì)應(yīng)的字段中

    將各個(gè)用戶對(duì)應(yīng)的屬性插入到目標(biāo)表對(duì)應(yīng)的字段中,last_update為數(shù)據(jù)更新日期
    2014-08-08
  • MySQL group by和order by如何一起使用

    MySQL group by和order by如何一起使用

    這篇文章主要介紹了MySQL group by和order by如何一起使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • 深入理解mysql的自連接和join關(guān)聯(lián)

    深入理解mysql的自連接和join關(guān)聯(lián)

    這篇文章主要給大家介紹了關(guān)于mysql的自連接和join關(guān)聯(lián)的相關(guān)資料,文中介紹的非常詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。
    2017-04-04
  • 最新評(píng)論