求教一個mysql建表分組索引問題
問題描述
我在做一個網站程序,大致要求效果如下。用戶分為1-5這五個級別,數字越大權限越高。
我有一堆內容,級別越高的用戶可見內容越多。例如有內容:A、B、C、D、E,用戶組1的可見:A用戶組2的可見:A、B…………用戶組5的可見:A、B、C、D、E如果要實現這種功能,該如何建立數據庫索引比較好呢?
之前有朋友跟我說在內容(topic)表加上一列'group',寫上可見的用戶等級1-5,然后建立group_tid的聯合索引。然后查詢tid<100周圍文章(例如當前用戶組為3)時的語句就是:SELECT * FROM topic WHERE group>=3 AND tid<100 LIMIT 10;可實際發現這種索引是先將group>3的所有數據讀出來,再進行選擇查詢。假如有100萬條數據,有50萬個group>3,該語句執行就要從50萬條種篩選,效率極低。
看起來單列的索引只適用于group=*這樣的限制條件,而不能是<或>。所以想在此請教各路大神,有沒有過類似的需求?如何正確建立索引或分表?深表感謝!
補充1:其實把問題改變一下,就是如何在mysql兩個索引中使用<或>限定。這是個邏輯問題,目前的group_tid索引建立后類似于下圖:
即便我對group進行了范圍限制,后面的tid還是在group的基礎上按順序排列的。如果我想知道group>1且tid<6的這種情況,不得不先把group2/3全部讀出再篩選。看起來只有重新規劃表結構,各位有沒有類似經驗?
補充2:剛才收到了熱心朋友的幫助回答,說這種情況他曾經遇到過。解決的方法是修改發布機制,將符合條件的帖子發布至各個等級。例如內容A的級別是3,那么發帖時要同時建立三個數據行:group=1,tid=Agroup=2,tid=Agroup=3,tid=A這樣在內容讀取時直接請求WHERE group=*都可以讀出符合條件內容。但這種方法需要添加大量的關聯數據,甚至造成重復,有沒有其他解決途徑呢?
問題解答
回答1:其實你的思路已經很對了。
tid上建立索引,根據group分表。
如果group >=3的組,在程序中動態組合sql如下:
select * from group3 where tid < 100union all select * from group4 where tid < 100union all select * from group5 where tid < 100
以上索引生效,邏輯可用。
回答2:首先說明一下,在 Innodb 中,索引生不生效跟你使用 < 或 > 沒有必然關系。也不是說用 = 就一定能用上索引。當全表查的性能要高于索引檢索查詢時,MySQL 會智能的放棄索引,選擇全表查詢。
如圖:
回到你的問題,如果某個索引,如 tid<100 檢索出的范圍相對較小時,索引是能夠用上的。
如果這兩個索引的結果集都很大的話,是否考慮添加其他過濾條件,比如根據創建時間只查近一個月的內容。
分頁問題也可以通過主鍵ID來再次過濾。
回答3:首先,需要明白以下幾點:
對于一個表的查詢,每次最多只使用一個索引
對于聯合索引,從左往右依次進行數據的篩選,所以如果第一個篩選條件針對了大于或者小于的話,第二個篩選條件由于在整個可選區域內沒有確切的索引范圍,所以會將第一個篩選條件篩除來的數據都跑一遍
B-Tree索引的結構類似于樹形結構,見下圖,聯合索引從左往右的檢索,起始就是這個結構從上往下查找分支的過程
索引的機制,簡單說來就是創建一個值到數據項的對應表,這樣可以快速的從某一字段某個值定位到某一行,省卻了跑整個表去找對應行的操作,所以比較快
B-Tree索引的結構:
然后回到你的問題上,如果要大幅度提高效率,那么聯合索引的第一步就需要大幅度減少可以用于后續篩選的數據量,所以如果你要查tid < 100的話,先用tid篩選才能夠大幅度減少后續的B-Tree索引分支,所以如果要用聯合索引,則應該是(tid, group)。
回答4:group條件的過濾性很差,單獨建立索引意義不大。
根據你描述的場景,只要tid的值不是太大(幾千的數量級),針對tid建立索引就可以了。如果還擔心tid條件過濾后的數據量大,可以創建tid,group的組合索引。
回答5:首先非常感謝各位對我問題的關注和回答!!問題解決之后針對boxsnake的建議有一個思考,在這里發一下。group_tid這種索引方式除了解決讀取之外還能解決分頁問題,例如我每頁文章數量是10,用戶級別為3,那么讀取時分別從group1、group2、group3中,按范圍tid<100各取10篇,即便某group中沒有符合條件的結果,幾項加起來也可以覆蓋全。
但如果用tid_group這種索引方式來讀取,如果需要group<=3的情況,我不知道該取多少篇文章。比方說取10篇,tid90-tid99,如果他們的group都是4,那么就無法取出符合條件的數值。而tid_group在限定group之前又必須對tid進行限定,所以就沒法使用了。
相關文章:
1. 一個走錯路的23歲傻小子的提問2. python - 請問matplotlib.pyplot.save的路徑如何更改3. python中的 + 不能和java一樣作為連接符么?4. python小白,問一個關于可變類型和不可變類型底層的問題5. python - Django前臺url未能正確訪問方法求助?6. mysql - SQL問個基礎例子,書上的,我怎么看都看不懂..誰幫我解釋一下第2個為什么和第1個一樣?7. python - Django問題 ’WSGIRequest’ object has no attribute ’user’8. javascript - js 對中文進行MD5加密和python結果不一樣。9. 數據庫 - mysql boolean型無法插入true10. mysql服務無法啟動1067錯誤,誰知道正確的解決方法?
