鍍金池/ 問答/數(shù)據(jù)庫/ mysql多表聯(lián)合查詢,加條件篩選,需要排序分頁,要求不使用join連接,要如何

mysql多表聯(lián)合查詢,加條件篩選,需要排序分頁,要求不使用join連接,要如何實現(xiàn)?

問題背景:

  • 有a、b、c三個表,a跟b、c都是一對多的關系,a有自增主鍵a.id,這是排序分頁的依據(jù),但按BOSS要求,不許在b、c表中添加a.id的冗余字段(包括外鍵手段,外鍵是使用的a中另一個保證唯一的定長字符串a(chǎn).guid);
  • b、c表中均有字段用于作篩選條件,且由于a跟b、c都是一對多的關系,無法在a表中添加b、c表的篩選用字段作冗余;
  • 說是由于預計數(shù)據(jù)量會非常大(百萬級),不允許使用join連接,且由于考慮以后遷移其他數(shù)據(jù)庫的可能性,不允許使用自增主鍵id做外鍵,包括不允許使用自增主鍵id作為其他表的冗余字段。

需求:

  • 獲取a表數(shù)據(jù)列表,分頁顯示,排序依據(jù)是a.id;
  • 有必選的篩選條件,在a表中,在此舉例為a.set;
  • 有可選的篩選條件,條件分別在b、c表中,在此舉例為b.type,c.name。

探索(此問題未解決,求助各位大佬幫忙):

  • 此問題的等價join連接SQL語句如下所示:

    SELECT a.id,a.guid,a.col1,a.col2 
    FROM a 
        INNER JOIN b ON a.guid = b.a_guid
        INNER JOIN c ON a.guid = c.a_guid
    WHERE a.set = 'xxx'          -- 必選條件
        AND b.type = 1           -- 整數(shù),可選篩選條件
        AND c.name LIKE '%XXX%'  -- 模糊查詢,可選篩選條件
    GROUP BY a.guid              -- 去重
    ORDER BY a.id                -- 按a.id排序
    LIMIT 0,10                   -- 分頁
    ;
  • 不允許使用join連接,故思路自然是添加冗余字段,問題背景也說明了a表無法添加b、c表的冗余字段,故在b、c表中都添加了a_set(即a.set)的冗余字段;
  • 若不考慮分頁,僅根據(jù)單獨的可選篩選條件自然可以先篩選出a.guid,如根據(jù)b.type篩選:

    SELECT b.a_guid FROM b WHERE b.a_set = 'xxx' AND b.type = 1 GROUP BY b.a_guid;
  • 但這樣問題自然在于b表中沒有a.id字段可供排序,無法進行分頁,分頁思路自然是上面的語句查詢出b.a_guid的結(jié)果集后,在a表中使用IN進行查詢,然后按a.id進行排序分頁,但此思路又有個問題是本身a、b、c三表的數(shù)據(jù)量預計就會很大,篩選出的b.a_guid的結(jié)果集可能也會非常大,可能會導致SQL語句超出長度限制,即便增加了SQL語句的長度限制或者使用子查詢的方法,但IN中的數(shù)據(jù)量太多的話,不也是會很影響查詢效率嗎,會不會效率還不如使用JOIN連接?
  • 就此,思路卡在此處,實在想不出好的解決方案,在此求助路過的大神幫忙,提供一下解決的思路
回答
編輯回答
替身

不想有冗余字段,那就建個關聯(lián)表,把a b 表的數(shù)據(jù)關聯(lián)起來,想排序就加個a.id,索引建起來。

最好不要用IN,In的效率比較低。很多時候JOIN的效率反而更高的,你用到JOIN了已經(jīng)涉及到多表了,關系型數(shù)據(jù)庫,干的就是關系,擅長的就是查詢;百萬級,其實ok的;就是控制一下join的表數(shù),關聯(lián)越多效率就越低。

根據(jù)你的業(yè)務來設計數(shù)據(jù)庫,業(yè)務體現(xiàn)數(shù)據(jù)未來可能的增長方向??梢韵扰繑]數(shù)據(jù)進去然后測一下sql效率看看。

2018年5月16日 17:52