Django ORM与Oracle的性能不佳

ape*_*rov 11 oracle django orm cx-oracle sqlalchemy

我正在构建一个带有Oracle后端的Django网站,即使在对主键进行简单查找时,我也观察到性能非常慢.当在MySQL中加载相同的数据时,相同的代码工作得非常快.

可能是表现不佳的原因是什么?我怀疑这个问题与使用Oracle绑定参数有关,但情况可能并非如此.

Django模型(一个约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'
Run Code Online (Sandbox Code Playgroud)

Django ORM(需要~1s)

from myapp.models import *
r = Mytable.objects.get(upi='xxxxxxxxxxxxx')
Run Code Online (Sandbox Code Playgroud)

带有绑定参数的原始查询(需要~1s)

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

没有绑定参数的原始查询(瞬时)

cursor.execute("SELECT * FROM mytable WHERE upi = 'xxxxxxxxxxxxx'")
row = cursor.fetchone()
print row
Run Code Online (Sandbox Code Playgroud)

我的环境

  • Python 2.6.6
  • Django 1.5.4
  • cx-Oracle 5.1.2
  • Oracle 11g

连接到Oracle数据库时,我指定:

'OPTIONS': {
    'threaded': True,
}
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激.

[更新] 我使用debugsqlshellDjango调试工具栏中的工具做了一些进一步的测试.

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

这表明Django使用Oracle绑定参数,并且查询本身非常快,但创建相应的Python对象需要很长时间.

为了确认,我使用cx_Oracle运行相同的查询(请注意,cursor我原来的问题是Django游标).

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()
Run Code Online (Sandbox Code Playgroud)

什么可能减慢Django ORM?

[更新2]我们从Oracle端查看了数据库性能,结果发现当查询来自Django时不使用索引.任何想法为什么会出现这种情况?

ape*_*rov 1

与我们的 DBA 合作后,发现由于某种原因 Djangoget(upi='xxxxxxxxxxxx')查询没有使用数据库索引。

当使用 重写相同的查询时filter(upi='xxxxxxxxxxxx')[:1].get(),查询速度很快。

get仅使用整数主键(原始问题中是字符串)的查询速度才快。

最终解决方案

create index index_name on Mytable(SYS_OP_C2C(upi));
Run Code Online (Sandbox Code Playgroud)

cx_Oracle 和 Oracle 使用的字符集之间似乎存在一些不匹配。添加 C2C 索引可以解决该问题。

更新:此外,在 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