2013-09-24 30 views
11

我正在構建一個帶有Oracle後端的Django網站,即使在主鍵上進行簡單查找時,我也觀察到性能非常低下。當相同的數據在MySQL中加載時,相同的代碼工作速度非常快。Django ORM與Oracle性能差

什麼可能是性能不佳的原因?我懷疑這個問題與使用Oracle綁定參數有關,但這可能並非如此。

的Django模型(測試用〜6200000行表)

from django.db import models 

class Mytable(models.Model): 
    upi = models.CharField(primary_key=True, max_length=13) 

    class Meta: 
     db_table = 'mytable' 

Django的ORM(取〜1S)

from myapp.models import * 
r = Mytable.objects.get(upi='xxxxxxxxxxxxx') 

與綁定參數原始查詢(取〜 1s)

cursor.execute("SELECT * FROM mytable WHERE upi = %s", ['xxxxxxxxxxxxx']) 
row = cursor.fetchone() 
print row 

沒有綁定原始查詢參數(瞬時)

cursor.execute("SELECT * FROM mytable WHERE upi = 'xxxxxxxxxxxxx'") 
row = cursor.fetchone() 
print row 

我的環境

  • 的Python 2.6.6
  • 的Django 1.5.4
  • CX-甲骨文5.1.2
  • Oracle 11g

當連接到Oracle數據庫我註明:

'OPTIONS': { 
    'threaded': True, 
} 

任何幫助將不勝感激。

[更新] 我沒有使用從Django的調試工具欄debugsqlshell工具的一些進一步的測試。

# takes ~1s 
>>>Mytable.objects.get(upi='xxxxxxxxxxxxx') 
SELECT "Mytable"."UPI" 
FROM "Mytable" 
WHERE "Mytable"."UPI" = :arg0 [2.70ms] 

這表明,Django使用了Oracle綁定參數,並查詢本身是非常快的,但是創建相應的Python對象需要很長的時間。

爲了確認,我使用cx_Oracle運行了相同的查詢(請注意,我原來的問題中的cursorDjango cursor)。

import cx_Oracle 
db= cx_Oracle.connect('connection_string') 
cursor = db.cursor() 

# instantaneous 
cursor.execute('SELECT * from mytable where upi = :upi', {'upi':'xxxxxxxxxxxxx'}) 
cursor.fetchall() 

什麼可能會減緩Django ORM?

[更新2]我們查看了Oracle方面的數據庫性能,結果發現,當查詢來自Django時,不會使用該索引。任何想法,爲什麼這可能是這種情況?

+0

你檢查查找字段上的索引存在於數據庫? – esauro

+0

當我檢查SQL Developer中的表時,我發現該列上有一個有效的正常索引。 – apetrov

+0

如果您在SQL Developer中運行2個版本並且查詢計劃不同(使用解釋計劃或自動跟蹤按鈕),會發生什麼情況?對於綁定變量,使用'SELECT * FROM mytable WHERE upi =:s',SQL Developer會提示您輸入值。 –

回答

1

與我們的數據庫管理員一起工作後,事實證明,由於某些原因,Django get(upi='xxxxxxxxxxxx')查詢未使用數據庫索引。

當使用filter(upi='xxxxxxxxxxxx')[:1].get()重寫相同的查詢時,查詢很快。

get查詢速度很快,只有整數主鍵(它是原始問題中的字符串)。

最終解決

create index index_name on Mytable(SYS_OP_C2C(upi)); 

有似乎是cx_Oracle和Oracle使用的字符集之間有一些不匹配。添加C2C索引可修復問題。

UPDATE: 另外,從Oracle中的VARCHAR2切換到NVARCHAR2具有相同的效果,可用於替代功能索引。

下面是一些有用的討論話題,幫助我: http://comments.gmane.org/gmane.comp.python.db.cx-oracle/3049 http://comments.gmane.org/gmane.comp.python.db.cx-oracle/2940

2

使用TO_CHAR(character)要解決性能問題:

cursor.execute("SELECT * FROM mytable WHERE upi = TO_CHAR(%s)", ['xxxxxxxxxxxxx'])