最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解分庫(kù)分表后非分片鍵如何查詢(xún)

 更新時(shí)間:2023年03月10日 14:09:56   作者:飄渺Jam  
這篇文章主要為大家介紹了分庫(kù)分表后非分片鍵如何查詢(xún)?cè)斀?,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

我們知道在分庫(kù)分表中對(duì)于toC業(yè)務(wù)來(lái)說(shuō),需要選擇用戶(hù)屬性如 user_id 作為分片鍵,不推薦使用order_id這樣的作為分片鍵。

那問(wèn)題來(lái)了,對(duì)于訂單表來(lái)說(shuō),選擇了user_id作為分片鍵以后如何查看訂單詳情呢?比如下面這樣一條SQL:

SELECT * FROM T_ORDER WHERE order_id = 801462878019256325

由于查詢(xún)條件中的order_id不是分片鍵,所以需要查詢(xún)所有分片才能得到最終的結(jié)果。如果下面有 1000 個(gè)分片,那么就需要執(zhí)行 1000 次這樣的 SQL,這時(shí)性能就比較差了。

可以通過(guò)ShardingSphere-JDBC生成的SQL得知,根據(jù)order_id查詢(xún)會(huì)對(duì)所有分片進(jìn)行查詢(xún)?nèi)缓笸ㄟ^(guò)UNION ALL進(jìn)行合并。

但是,我們知道 order_id 是主鍵,應(yīng)該只有一條返回記錄,也就是說(shuō),order_id 只存在于一個(gè)分片中。這時(shí),可以有以下三種設(shè)計(jì):

  • 冗余數(shù)據(jù)法
  • 索引表法
  • 基因分片法

當(dāng)然,這三種設(shè)計(jì)的本質(zhì)都是通過(guò)冗余實(shí)現(xiàn)空間換時(shí)間的效果,否則就需要掃描所有的分片,當(dāng)分片數(shù)據(jù)非常多,效率就會(huì)變得極差。

下面我們逐一分析。

設(shè)計(jì)一:冗余法

這種做法很容易理解,同一份訂單數(shù)據(jù)在插入時(shí)保存兩份,根據(jù)user_id 和 order_id分別做兩個(gè)分庫(kù)分表的實(shí)現(xiàn)。

通過(guò)對(duì)表進(jìn)行冗余,對(duì)于 order_id 的查詢(xún),只需要在 order_id = 801462878019256325 的分片中直接查詢(xún)就行,效率最高。但是這個(gè)方案設(shè)計(jì)的缺點(diǎn)又很明顯:冗余數(shù)據(jù)量太大。

方法二:索引表法

索引表法是對(duì)第一種冗余法的改進(jìn),由于第一種方案冗余的數(shù)據(jù)量太大,所以索引表方案中只創(chuàng)建一個(gè)包含user_id和order_id的索引表,在插入訂單時(shí)再插入一條數(shù)據(jù)到索引表中。

表結(jié)構(gòu)如下

CREATE TABLE idx_orderid_userid (
  order_id bigint
  user_id bigint,
  PRIMARY KEY (order_id)
)

在實(shí)現(xiàn)時(shí)可以將idx_orderid_userid表通過(guò)Redis緩存來(lái)代替,如果此表數(shù)據(jù)量很大也可以將其分庫(kù)分表,但是它的分片鍵是 order_id。

如果這時(shí)再根據(jù)字段 order_id 進(jìn)行查詢(xún),可以進(jìn)行類(lèi)似二級(jí)索引的回表實(shí)現(xiàn):先通過(guò)查詢(xún)索引表得到記錄 order_id = 801462878019256325 對(duì)應(yīng)的分片鍵 user_id 的值,接著再根據(jù) user_id 進(jìn)行查詢(xún),最終定位到想要的數(shù)據(jù),如:

原始SQL:

SELECT * FROM T_ORDER WHERE order_id = 801462878019256325

拆分后的SQL:

# step 1
SELECT user_id FROM idx_orderid_userid 
WHERE order_id = 801462890610556951
?
# step 2
SELECT * FROM T_ORDER 
WHERE user_id = ? AND order_id = 801462890610556951

這個(gè)例子是將一條 SQL 語(yǔ)句拆分成 2 條 SQL 語(yǔ)句,但是拆分后的 2 條 SQL 都可以通過(guò)分片鍵進(jìn)行查詢(xún),這樣能保證只需要在單個(gè)分片中完成查詢(xún)操作。不論有多少個(gè)分片,也只需要查詢(xún) 2個(gè)分片的信息,這樣 SQL 的查詢(xún)性能可以得到極大的提升。

方法三:基因法

通過(guò)索引表的方式,雖然存儲(chǔ)上較冗余全表容量小了很多,但是要根據(jù)另一個(gè)分片鍵進(jìn)行數(shù)據(jù)的存儲(chǔ),還是顯得不夠優(yōu)雅。

因此,最優(yōu)的設(shè)計(jì),不是創(chuàng)建一個(gè)索引表,而是將分片鍵的信息保存在想要查詢(xún)的列中,這樣通過(guò)查詢(xún)的列就能直接知道所在的分片信息,這種方法也叫叫做基因法。

基因法的原理出自一個(gè)理論:對(duì)一個(gè)數(shù)取余2的n次方,那么余數(shù)就是這個(gè)數(shù)的二進(jìn)制的最后n位數(shù)。

假如我們現(xiàn)在根據(jù)user_id進(jìn)行分片,采用user_id % 16的方式來(lái)進(jìn)行數(shù)據(jù)庫(kù)路由,這里的user_id%16,其本質(zhì)是user_id的最后4個(gè)bit位 log(16,2) = 4 決定這行數(shù)據(jù)落在哪個(gè)分片上,這4個(gè)bit就是分片基因。

如上圖所示,user_id=20160169的用戶(hù)創(chuàng)建了一個(gè)訂單(20160169的二進(jìn)制表示為:1001100111001111010101001)

  • 使用user_id%16分片,決定這行數(shù)據(jù)要插入到哪個(gè)分片中
  • 分庫(kù)基因是user_id的最后4個(gè)bit,log(16,2) = 4,即1001
  • 在生成order_id時(shí),先使用一種分布式ID生成算法生成前60bit(上圖中綠色部分)
  • 將分庫(kù)基因加入到order_id的最后4個(gè)bit(上圖中粉色部分)
  • 拼裝成最終的64bit訂單order_id(上圖中藍(lán)色部分)

這樣保證了同一個(gè)用戶(hù)創(chuàng)建的所有訂單都落到了同一個(gè)分片上,order_id的最后4個(gè)bit都相同,于是:

  • 通過(guò)user_id %16 能夠定位到分片
  • 通過(guò)order_id % 16也能定位到分片

不好理解的話(huà),可以看下面這段代碼:

@Test
public void modIdTest(){
    long userID = 20160169L;
    //分片數(shù)量
    int shardNum = 16;
    String gen = getGen(userID, shardNum);
    log.info("userID:{}的基因?yàn)?{}",userID,gen);
    long snowId = IdWorker.getId(Order.class);
    log.info("雪花算法生成的訂單ID為{}",snowId);
    Long orderId = buildGenId(snowId,gen);
    log.info("基因轉(zhuǎn)換后的訂單ID為{}",orderId);
?
    Assert.assertEquals(orderId % shardNum , userID % shardNum);
}

運(yùn)行結(jié)果如下:

原始訂單ID為1595662702879973377,通過(guò)基因轉(zhuǎn)換后ID變成了1595662702879973385,對(duì)于用戶(hù)id 和 新生成的訂單id對(duì)其取模結(jié)果一樣。

上面那種做法是基因替換,替換掉訂單id的分片基因。下面這種做法就更顯直接。

將訂單表 orders 的主鍵設(shè)計(jì)為一個(gè)字符串,這個(gè)字符串中最后一部分包含分片鍵的信息,如:

order_id = string(order_id + user_id)

那么這時(shí)如果根據(jù) order_id 進(jìn)行查詢(xún):

SELECT * FROM T_ORDER
WHERE order_id = '1595662702879973377-20160169';

由于字段 order_id 的設(shè)計(jì)中直接包含了分片鍵信息,所以我們可以直接通過(guò)分片鍵部分直接定位到分片上。

同樣地,在插入時(shí),由于可以知道插入時(shí) user_id 對(duì)應(yīng)的值,所以只要在業(yè)務(wù)層做一次字符的拼接,然后再插入數(shù)據(jù)庫(kù)就行了。

這樣的實(shí)現(xiàn)方式較冗余表和索引表的設(shè)計(jì)來(lái)說(shuō),效率更高,查詢(xún)時(shí)可以直接定位到數(shù)據(jù)對(duì)應(yīng)的分片信息,只需 1 次查詢(xún)就能獲取想要的結(jié)果。

這樣實(shí)現(xiàn)的缺點(diǎn)是,主鍵值會(huì)變大一些,存儲(chǔ)也會(huì)相應(yīng)變大。但是只要主鍵值是有序的,插入的性能就不會(huì)變差。而通過(guò)在主鍵值中保存分片信息,卻可以大大提升后續(xù)的查詢(xún)效率,這樣空間換時(shí)間的設(shè)計(jì),總體上看是非常值得的。

實(shí)際上淘寶的訂單號(hào)也是這樣構(gòu)建的

上圖是我的淘寶訂單信息,可以看到,訂單號(hào)的最后 6 位都是 607041,所以可以大概率推測(cè)出:

  • 淘寶訂單表的分片鍵是用戶(hù) ID;
  • 淘寶訂單表,訂單表的主鍵包含用戶(hù) ID,也就是分片信息。這樣通過(guò)訂單號(hào)進(jìn)行查詢(xún),可以獲得分片信息,從而查詢(xún) 1 個(gè)分片就能得到最終的結(jié)果。

小結(jié)

分庫(kù)分表后需要遵循一個(gè)基本原則:所有的查詢(xún)盡量帶上sharding key,有時(shí)候業(yè)務(wù)需要根據(jù)技術(shù)限制進(jìn)行妥協(xié),那種既要...又要...就是在耍流氓。

當(dāng)然有些業(yè)務(wù)場(chǎng)景確實(shí)沒(méi)辦法避免,對(duì)于非sharding key的查詢(xún)可以參考上面三種方案實(shí)現(xiàn),不過(guò)實(shí)際上只能算兩種。

曾經(jīng)在面試時(shí)我還被問(wèn)到過(guò)這個(gè)問(wèn)題~

今天的文章是屬于理論知識(shí),Talk is cheap,Show me the code! 接下來(lái)兩篇文章我將結(jié)合ShardingSphere-JDBC實(shí)現(xiàn)上述兩種方案,更多關(guān)于分庫(kù)分表非分片鍵查詢(xún)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Doris?數(shù)據(jù)模型ROLLUP及前綴索引官方教程

    Doris?數(shù)據(jù)模型ROLLUP及前綴索引官方教程

    本文檔主要從邏輯層面,描述 Doris 的數(shù)據(jù)模型 ROLLUP 以及前綴索引的概念,以幫助用戶(hù)更好的使用 Doris 應(yīng)對(duì)不同的業(yè)務(wù)場(chǎng)景,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Navicat使用快速入門(mén)教程

    Navicat使用快速入門(mén)教程

    這篇文章主要介紹了Navicat使用快速入門(mén)教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • mssql 區(qū)分大小寫(xiě)的詳細(xì)說(shuō)明

    mssql 區(qū)分大小寫(xiě)的詳細(xì)說(shuō)明

    mssql區(qū)分大小寫(xiě),沒(méi)想到mysql也區(qū)分大小寫(xiě)。相關(guān)的文章稍后奉獻(xiàn)給大家
    2008-03-03
  • DBeaver連接GBase數(shù)據(jù)庫(kù)的簡(jiǎn)單步驟記錄

    DBeaver連接GBase數(shù)據(jù)庫(kù)的簡(jiǎn)單步驟記錄

    DBeaver數(shù)據(jù)庫(kù)連接工具,是我用了這么久最好用的一個(gè)數(shù)據(jù)庫(kù)連接工具,擁有的優(yōu)點(diǎn),支持的數(shù)據(jù)庫(kù)多、快捷鍵很贊、導(dǎo)入導(dǎo)出數(shù)據(jù)非常方便,下面這篇文章主要給大家介紹了關(guān)于DBeaver連接GBase數(shù)據(jù)庫(kù)的簡(jiǎn)單步驟,需要的朋友可以參考下
    2024-03-03
  • SQL中一些小巧但常用的關(guān)鍵字小結(jié)

    SQL中一些小巧但常用的關(guān)鍵字小結(jié)

    這篇文章主要給大家總結(jié)介紹了關(guān)于SQL中一些小巧但常用的關(guān)鍵字,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • SQL查詢(xún)連續(xù)號(hào)碼段的巧妙解法

    SQL查詢(xún)連續(xù)號(hào)碼段的巧妙解法

    在ITPUB上有一則非常巧妙的SQL技巧,學(xué)習(xí)一下,記錄在這里
    2013-09-09
  • 你真的知道怎么優(yōu)化SQL嗎

    你真的知道怎么優(yōu)化SQL嗎

    這篇文章主要給大家介紹了關(guān)于優(yōu)化SQL的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用SQL具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 一文讀懂?dāng)?shù)據(jù)庫(kù)管理工具 Navicat 和 DBeaver

    一文讀懂?dāng)?shù)據(jù)庫(kù)管理工具 Navicat 和 DBeaver

    這篇文章主要介紹了數(shù)據(jù)庫(kù)管理工具 Navicat 和 DBeaver的相關(guān)資料,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • 使用DataGrip連接Hive的詳細(xì)步驟

    使用DataGrip連接Hive的詳細(xì)步驟

    這篇文章主要介紹了DataGrip連接Hive的詳細(xì)圖文教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 90%程序員面試會(huì)遇到的索引優(yōu)化問(wèn)題

    90%程序員面試會(huì)遇到的索引優(yōu)化問(wèn)題

    不管是用C/C++/Java等代碼編寫(xiě)的程序,還是SQL編寫(xiě)的數(shù)據(jù)庫(kù)腳本,都存在一個(gè)持續(xù)優(yōu)化的過(guò)程。也就是說(shuō),代碼優(yōu)化對(duì)于程序員來(lái)說(shuō),是一個(gè)永恒的話(huà)題。下面這篇文章主要給大家總結(jié)介紹了90%程序員在面試的時(shí)候會(huì)遇到的索引優(yōu)化問(wèn)題,需要的朋友可以參考下。
    2017-11-11

最新評(píng)論

琼中| 同江市| 大荔县| 临朐县| 化隆| 原阳县| 镇康县| 安化县| 鄂托克旗| 济宁市| 侯马市| 桃园县| 滦平县| 锦州市| 康平县| 淳安县| 新干县| 仁化县| 呼和浩特市| 子洲县| 吐鲁番市| 鹤岗市| 汾西县| 定边县| 清丰县| 竹北市| 蕲春县| 定安县| 略阳县| 上犹县| 敦化市| 广元市| 鄂尔多斯市| 长子县| 永善县| 庆安县| 石嘴山市| 河池市| 莱阳市| 新闻| 六枝特区|