2016-12-03 53 views
2

對於排名系統(在擁有數萬用戶的數據庫中),我想按用戶總數排列三列: Points_A,Points_BPoints_C。我想知道這將是一個更好的選擇:總列或新列

  • 每個被訪問排名網頁時,通過總和所有列和順序相加計算用戶的排名
  • 創建一個新列Points_total與三列的總和(我每次更新其他列之一時更新總數),並按此Points_total排序查詢。

排名頁面可能每秒要求多次,所以表現非常重要。第二種選擇更快還是不推薦?

+1

最好的辦法就是試試更簡單的方法(不存儲總和),看看性能是否可以接受*。不是哪一個更好,因爲不管多困難多少,比方說,它的速度要快1000倍,比如它需要從120毫秒到少於一飛秒的延遲,120毫秒對於一個頁面來說足夠快加載。即只有在顯着影響用戶體驗的情況下,性能才非常重要。 –

回答

3

從MySQL 5.7.6開始,您可以創建生成的列,使您能夠根據表中其他列中的其他值存儲虛擬值。

CREATE TABLE tbl (
    Points_A INT, 
    Points_B INT, 
    Points_C INT, 
    Points_total INT AS (Points_A + Points_B + Points_C) 
); 

生成列定義具有以下語法:

COL_NAME DATA_TYPE [總是GENERATED] AS(表達式)
    [VIRTUAL | STORED] [UNIQUE [KEY] [註釋評論]
    [NOT] NULL] [PRIMARY] KEY]

您可以決定使用VIRTUALSTORED(取決於你的需要)。

從MySQL 5.7.8開始,你也可以添加INDEXes on virtual columns,所以在你的情況下 - 這正是你正在尋找的(這種方式列中的值被索引)。

如果您使用的是比5.7.8更早的MySQL,並且多次訪問排名頁面 - 我建議您將特定列中的計算值相同並在該列上添加索引。

+0

如果OP有成千上萬的用戶,那麼需求可能需要一個索引。 –

+0

注意:某些時候(數百萬用戶?)重複更新索引的成本將會過高。成本本質上是「從BTree(索引)中刪除一行並將其重新插入到其他地方」。 –

0

這是一個想法。而不是在排名的每一個變化上採取昂貴的行動,看看這個複雜的方法可能會更好:

但首先,這取決於Points只增加,從不減少。它還假定你只需要排在前10名。並且不關心發現「我在10000中排名7654」)

設置一個觸發器(或應用程序代碼),每當排名增加時都會作出反應。它將點加在一起並根據閾值進行檢查。如果低於第10位的值,則不要做任何事情。

如果更高,則執行SELECT ... ORDER BY ... LIMIT 10以獲得新的「前10位」並將結果存儲在單獨的表中。另外,更新閾值。

可能好處:

  • 這個單獨的表是什麼是訪問「多次每一秒」,但主表不需要。
  • 做最少的工作(?)的時間少。 (但是對於投入很多的東西需要做更多的工作。)
  • 從主表(10K行)中分離出等級顯示錶(10行),從而減少鎖爭用。
  • 可以是用例的查詢緩存:
    • 打開它,
    • 設置query_cache_size = 20M(不要太大),
    • query_cache_type = DEMAND
    • 添加SQL_CACHE到基層SELECT;將SQL_NO_CACHE添加到其他大多數SELECTs

如果你需要的不僅僅是一個的「前10名」頁多,考慮到節約「前50名」。對於前5頁,新表就足夠了。對於第6頁及更高版本,請以硬方式進行(掃描10K行表格)。希望這將會是非常罕見的,仍然是一個優勢。