2015-10-05 47 views
1

表現我設計一個data-tables驅動的Django應用程序,並有data-tables電話與AJAX(我使用其服務器端處理模式data-tables)的API視圖。它實現搜索,分頁和排序。在Django視圖狀態保持改善分頁

我的數據庫最近變大了(大約500,000個條目),性能受到很大影響,無論是搜索還是轉到下一頁。我懷疑我寫這個觀點的方式是非常低效的。下面是我在視圖中執行(假設在我的數據庫中的對象是比薩):

  • filtered = Pizza.objects.filter(...)獲得一系列符合搜索條件的比薩餅。 (或者如果沒有搜索標準,則爲Pizza.objects.all())。

  • paginated = filtered[start: start + length]只得到當前的比薩餅頁面。 (最多隻有100個)。根據用戶所在的頁面,從data-tables客戶端代碼傳入開始和長度。

  • pizzas = paginated.order_by(...)將排序應用於當前頁面。

然後我將pizzas轉換成JSON並從視圖中返回它們。

看起來,儘管搜索對於500,000個條目來說可能是一個緩慢的操作,但移動到下一個頁面不應該要求我們重做整個搜索。所以我想要做的是在視圖中緩存一些東西(這是一個基於類的視圖)。我會跟蹤最後一個搜索字符串是什麼,以及它生成的一組結果。

然後,如果請求通過並且搜索字符串沒有不同(如果用戶點擊了幾頁結果,會發生什麼情況),我不必再次點擊數據庫以獲取過濾器結果 - 我只能使用緩存版本。

這是一個只讀應用程序,所以不同步不會是一個問題。

我甚至可以保留一大堆搜索字符串和他們應該產生的比薩餅的字典。

我想知道的是:這是對問題的合理解決方案嗎?還是有我忽略的東西?另外,我在這裏重新發明車輪嗎?這並不是說這不易實施,但是QuerySet還有一個內置的選項,或者可以做到這一點?

回答

2

pizzas = paginated.order_by(...)很慢,它將所有匹薩分類爲不是當前頁面。索引幫助:https://docs.djangoproject.com/en/1.8/topics/db/optimization/#use-standard-db-optimization-techniques

如果您確實需要緩存,請檢出https://github.com/Suor/django-cacheops,「支持自動或手動查詢集緩存和自動細粒度事件驅動失效的流暢應用程序。」

+0

哇,這是真的嗎?如果我先切片查詢集,然後做過濾/排序/無論它,它實際上是過濾/命令/任何然後切片? –

+0

根據django 1.8的文檔,「對未評估的QuerySet進行切片會返回另一個未評估的QuerySet,因此不允許對其進行進一步修改(例如,添加更多過濾器或修改排序)」。所以看起來我部分錯了,'pizzas = paginated.order_by(...)'是不允許的。仍然「考慮將索引添加到您經常使用filter(),exclude(),order_by()查詢的字段」 – JimmyYe

1

有改進代碼結構的多個方式,

首先是你只獲取其是根據使用Django ORM打你的網頁數量要求的數據,第二個是你緩存你的ORM輸出和再利用,導致如果相同的查詢再次傳遞。

先是這樣。

在你的代碼

Pizza.objects.all() paginated = filtered[start: start + length] 你是第一個獲取所有數據,那麼,你是切片的是,這是非常昂貴的SQL查詢,將其轉換成

filtered = Pizza.objects.all()[(page_number-1) * 30, (page_number-1) * 30 + 30]

上面給出的ORM會只獲取那些根據提供的頁碼數的行,並且非常快速地獲取所有行然後進行分片。

第二種方式,是根據查詢端起上,像內存緩存或redis的,當你需要從數據庫中獲取數據下一次高速緩存解決方案,則首先檢查數據是否存在首先獲取數據在該查詢的緩存中,如果存在,則只需使用該數據,因爲內存緩存解決方案比從數據庫獲取數據要快得多,因爲內存和硬盤驅動器之間的輸入輸出傳輸量非常大,而且我們知道傳統上硬盤驅動器慢。