2013-09-24 1 views
11

Я создаю сайт Django с бэкэдом Oracle, и я наблюдаю очень медленную производительность даже при простых проверках первичного ключа. Тот же код работает очень быстро, когда одни и те же данные загружаются в MySQL.Неудовлетворительная производительность Django ORM с Oracle

В чем причина плохой работы? У меня есть подозрение, что проблема связана с использованием параметров привязки Oracle, но это может быть не так.

Джанго модель (тестовый стол с ~ 6,200,000 строк)

from django.db import models 

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

    class Meta: 
     db_table = 'mytable' 

Джанго ОРМ (занимает ~ 1 сек)

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
  • ого-Oracle 5.1.2
  • Oracle 11g

При подключении к базе данных Oracle Уточняю:

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

Любая помощь будет принята с благодарностью.

[Update] Я сделал некоторые дальнейшие испытания с использованием debugsqlshell инструмента на панели инструментов отладки Django.

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

Это говорит о том, что Django использует параметры связывания Oracle, а сам запрос очень быстро, но создает соответствующий объект Python занимает очень много времени.

Просто для подтверждения, я выполнил тот же запрос, используя cx_Oracle (обратите внимание, что cursor в моем исходном вопросе - Django 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

Что произойдет, если вы запустите 2 версии в SQL Developer и планируете разные варианты (используйте кнопки Explain Plan или Autotrace)? Для переменных привязки используйте '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 устраняет проблему.

ОБНОВЛЕНИЕ: Кроме того, переключение на NVARCHAR2 из VARCHAR2 в Oracle имеет тот же эффект, и может быть использован вместо функционального индекса.

Вот некоторые полезные обсуждения темы, которые помогли мне: 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']) 
Смежные вопросы