2010年4月28日 星期三

從 mysql 中隨機取出千筆資料 (別用 order by rand())

前陣子看到這篇提到別在 mysql 裡用 order by rand()。若有 1m 筆資料, order by rand() 相當於呼叫 1m 次 rand() 再做排序。可以想見速度不會快。若想取出隨機的資料, 視情況有不同的取代方案。注意 django 裡的 order_by('?') 轉換後的 sql 就是 order by rand(), 別用它。

若 table 有個流水號 id, 且沒有刪過資料, 可以先產生 1 ~ max(id) 之間的數字, 再用 id in (...) 取出隨機的資料。用 Django 的 ORM 來表示大概長這樣:
from django.db.models import Max
import random

mid = MyTable.objects.aggregate(Max('id'))['id__max']
ids = random.sample(xrange(1, mid + 1), 1000)
MyTable.objects.filter(id__in=ids)  # 隨機取出 1000 筆資料

若有刪過資料的話, 可能就多取幾筆最後再取前 1000 筆, 或是先取出所有 id 存下來再 sample 吧。

我自己測的結果, 百萬筆的資料用 order_by('?') 要數秒, 但改用 id__in 的寫法則是瞬殺。

沒有留言:

張貼留言

在 Fedora 下裝 id-utils

Fedora 似乎因為執行檔撞名,而沒有提供 id-utils 的套件 ,但這是使用 gj 的必要套件,只好自己編。從官網抓好 tarball ,解開來編譯 (./configure && make)就是了。 但編譯後會遇到錯誤: ./stdio.h:10...