11

我正在构建一个带有 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'

Django ORM(大约需要 1 秒)

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

带有绑定参数的原始查询(大约需要 1 秒)

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-Oracle 5.1.2
  • 甲骨文 11g

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

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

任何帮助将不胜感激。

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

# 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时,没有使用索引。任何想法为什么会这样?

4

2 回答 2

2

使用TO_CHAR(character)应该可以解决性能问题:

cursor.execute("SELECT * FROM mytable WHERE upi = TO_CHAR(%s)", ['xxxxxxxxxxxxx'])
于 2014-09-05T10:19:22.187 回答
1

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

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

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

最终解决方案

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

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

于 2013-10-10T09:05:28.870 回答