2013-09-24 33 views
11

Tôi đang xây dựng trang web Django với chương trình phụ trợ của Oracle và tôi quan sát hiệu suất rất chậm ngay cả khi thực hiện tra cứu đơn giản trên khóa chính. Cùng một mã hoạt động rất nhanh khi cùng một dữ liệu được tải trong MySQL.Hiệu suất kém của Django ORM với Oracle

Điều gì có thể là lý do cho hiệu suất kém? Tôi có một nghi ngờ rằng vấn đề có liên quan đến việc sử dụng các tham số liên kết Oracle, nhưng điều này có thể không phải là trường hợp.

Django mô hình (một bảng thử nghiệm với ~ 6.200.000 hàng)

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 (mất ~ 1s)

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

truy vấn liệu với các thông số ràng buộc (mất ~ 1s)

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

truy vấn liệu không có ràng buộc thông số (tức thời)

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

Môi trường của tôi

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

Khi kết nối với cơ sở dữ liệu Oracle tôi chỉ định:

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

Bất kỳ trợ giúp sẽ được đánh giá cao.

[Cập nhật] Tôi đã thực hiện thêm một số thử nghiệm bằng công cụ debugsqlshell từ thanh công cụ gỡ lỗi Django.

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

Điều này cho thấy Django sử dụng tham số liên kết Oracle và truy vấn rất nhanh, nhưng việc tạo đối tượng Python tương ứng mất một thời gian rất dài.

Chỉ cần xác nhận, tôi đã chạy cùng một truy vấn bằng cách sử dụng cx_Oracle (lưu ý rằng cursor trong câu hỏi ban đầu của tôi là 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() 

Điều gì có thể làm chậm xuống Django ORM?

[Cập nhật 2] Chúng tôi đã xem xét hiệu suất cơ sở dữ liệu từ phía Oracle và chỉ ra rằng chỉ mục này không được sử dụng khi truy vấn đến từ Django. Bất kỳ ý tưởng tại sao điều này có thể là trường hợp?

+0

Bạn có kiểm tra các chỉ số cho lĩnh vực tra cứu tồn tại trong db? – esauro

+0

Khi tôi kiểm tra bảng trong SQL Developer, tôi thấy rằng có một chỉ số bình thường hợp lệ trên cột đó. – apetrov

+0

Điều gì sẽ xảy ra nếu bạn chạy 2 phiên bản trong Nhà phát triển SQL và các kế hoạch truy vấn khác nhau (sử dụng các nút Giải thích Kế hoạch hoặc Tự động)? Đối với các biến liên kết, sử dụng 'SELECT * FROM mytable WHERE upi =: s' và SQL Developer sẽ nhắc bạn về giá trị. –

Trả lời

1

Sau khi làm việc với DBA của chúng tôi, hóa ra là vì một số lý do, truy vấn Django get(upi='xxxxxxxxxxxx') không sử dụng chỉ mục cơ sở dữ liệu.

Khi cùng một truy vấn được viết lại bằng cách sử dụng filter(upi='xxxxxxxxxxxx')[:1].get(), truy vấn nhanh.

Truy vấn get chỉ nhanh với các phím số nguyên chính (đó là chuỗi trong câu hỏi gốc).

CUỐI CÙNG GIẢI PHÁP

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

Dường như có một số không phù hợp giữa các bộ ký tự được sử dụng bởi cx_Oracle và Oracle. Việc thêm chỉ mục C2C sẽ khắc phục sự cố.

CẬP NHẬT: Ngoài ra, chuyển sang NVARCHAR2 từ VARCHAR2 trong Oracle có cùng tác dụng và có thể được sử dụng thay cho chỉ mục chức năng.

Dưới đây là một số chủ đề thảo luận hữu ích mà giúp tôi: http://comments.gmane.org/gmane.comp.python.db.cx-oracle/3049 http://comments.gmane.org/gmane.comp.python.db.cx-oracle/2940

2

Sử dụng TO_CHAR(character) nên giải quyết vấn đề hiệu suất:

cursor.execute("SELECT * FROM mytable WHERE upi = TO_CHAR(%s)", ['xxxxxxxxxxxxx']) 
Các vấn đề liên quan