升级到django 1.5后,Oracle查询速度变慢

时间:2015-07-03 05:25:40

标签: django oracle django-models

标题几乎说明了一切。我从Django 1.3升级到1.5.12,现在Oracle查询速度慢了10倍。据DBA称,查询通过Oracle Developer的运行时间不到1/2秒。

以下是型号:

class EsdPerson(models.Model):
    '''A partial user profile from the external read-only ESD database.
    Users may be indexed by ppid or netid.'''

    _id = models.AutoField(primary_key=True, db_column='prsn_i', editable=False)
    ppid = models.CharField(max_length=8, db_column='prsn_i_pblc',
            help_text="public person id/directory key")
    directory_name = models.CharField(max_length=75, db_column='prsn_n_full_dtry',
            help_text="full name in the online directory")
    ad_name = models.CharField(max_length=75, db_column='prsn_n_dspl_acdr',
            help_text="name in Active Directory")
    firstmid_name = models.CharField(max_length=20, db_column='prsn_n_fm_dtry',
            help_text="first and middle name in the online directory")
    last_name = models.CharField(max_length=25, db_column='prsn_n_last_dtry',
            help_text="last name in the online directory")
    name_suffix = models.CharField(max_length=15, db_column='prsn_n_sufx_dtry',
            help_text="honorary or other name suffix in the online directory")
    title = models.CharField(max_length=70, db_column='prsn_e_titl_dtry',
            help_text="position title in the online directory")
    phone = models.CharField(max_length=12, db_column='prad_a_tlph_empe_fmtt',
            help_text="phone number in the online directory")
    fax = models.CharField(max_length=12, db_column='prad_a_fax_empe_fmtt',
            help_text="fax number in the online directory")
    department_id = models.CharField(max_length=10, db_column='dprt_c',
            help_text="identifying code of the department the user works in")
    department_name = models.CharField(max_length=40, db_column='dprt8dtry_n',
            help_text="human-readable name of the department the user works in")
    division_code = models.CharField(max_length=10, db_column='dvsn_i',
            help_text="identifying code of the division the user works in")
    division_name = models.CharField(max_length=40, db_column='dvsn8dtry_n',
            help_text="human-readable name of the division the user works in")
    mailstop_code = models.CharField(max_length=12, db_column='mlst_i',
            help_text="identifying code of the user's mailstop")
    mailstop_name = models.CharField(max_length=30, db_column='mlst_n',
            help_text="human-readable name of the user's mailstop")

    netid = models.CharField(max_length=8, db_column='logn8ntwr_i',
            help_text="network login") # always all-caps
    internet_suppressed = YesNoBooleanField(db_column='prsn_f_sprs_intt',
            help_text="suppress user's directory information to off-campus clients")
    directory_suppressed = YesNoBooleanField(db_column='prsn_f_sprs_dtry',
            help_text="suppress user's directory information to all clients")
    information_suppressed = YesNoBooleanField(db_column='prsn_f_sprs_infr',
            help_text="no reference allowed to user")
    faculty_flag = YesNoBooleanField(max_length=1, db_column='empe_f_fclt',
            help_text="user is a faculty member")
    email = models.CharField(max_length=100, db_column='emad_n',
            help_text="user's primary email address")
    email_forward = models.CharField(max_length=100, db_column='emad8frwd_n',
            help_text="internal or external forwarding address for email")

    # default manager
    objects = models.Manager()
    faculty = EsdFacultyManager()
    'custom object manager for faculty persons only'

    # choice meanings per email from esd team
    EMPLOYEE_STATUS_CHOICES = (
        ('A', 'active'),
        ('D', 'deceased'),
        ('L', 'on leave'),
        ('O', 'on-boarding'), # ESDs term. not sure what it means
        ('P', 'sponsored'),
        ('T', 'terminated'),
    )
    employee_status = models.CharField(max_length=1, choices=EMPLOYEE_STATUS_CHOICES,
                                       db_column='emjo_c_stts_empe')

    # choice meanings per email from esd team
    PERSON_TYPE_CHOICES = (
        ('A', 'administrative'),
        ('B', 'student/staff'),
        ('C', 'staff/student'),
        ('E', 'staff'),
        ('F', 'faculty'),
        ('J', 'EU job eligible'),
        ('O', 'student applicant'),
        ('P', 'sponsored'),
        ('R', 'retired'),
        ('S', 'student'),
        ('U', 'unknown'),
        ('X', 'pre-start'),
    )
    person_type = models.CharField(max_length=1, db_column='prsn_c_type')


    class Meta:
        db_tablespace = 'esdv'
        # oracle tablespace requires this db_table syntax as of django
        # 1.3.1. mysql interprets it as a table name with quotes and a
        # period in it.
        db_table = '"esdv"."v_oem_fclt"'
        managed=False

    def __unicode__(self):
        return '%s (%s)' % (self.ppid, self.netid)

    @property
    def department_shortname(self):
        if ':' in self.department_name:
            return self.department_name[self.department_name.find(':')+1:].strip()
        return self.department_name

    def profile(self):
        '''Find the :class:`UserProfile` corresponding to this
        :class:`EsdPerson`.
        '''
        return UserProfile.objects.get(user__username=self.netid.lower())

    def has_profile_page(self):
        '''Return ``True`` if the user should have a public-facing web
        profile on the site, ``False`` if not.  Currently requires
        Faculty status.
        '''
        return self.person_type == 'F'

    # additional field mappings for solr indexing
    @property
    def id(self):
        'Id for use as Solr common id - `ppid:P####`, based on :attr:`ppid`.'
        return 'ppid:%s' % self.ppid

    _first_name = None

    @property
    def first_name(self):
        '''First and middle name for indexing in Solr.

        Uses :attr:`firstmid_name` when available; if empty, attempts
        to infer first name based on :attr:`last_name` and
        :attr`ad_name`.
        '''
        if self._first_name is None:
            # if first-middle directory name is available, use it
            if self.firstmid_name:
                self._first_name = self.firstmid_name

            # otherwise, if both last name and ad name are available and match,
            # infer first name from ad name (ad name format: lastname, first middle)
            elif self.last_name and self.ad_name and self.ad_name.startswith(self.last_name):
                self._first_name = self.ad_name[len(self.last_name):].strip(' ,')

        return self._first_name

    @property
    def username(self):
        'Lower-case form of :attr:`netid`, for indexing in Solr.'
        return self.netid.lower()
    record_type = 'accounts_esdperson'
    'record type for Solr index, to distinguish from other indexed content'
    # following django contenttype convention: app_label, model

    @property
    def division_dept_id(self):
        '''Delimited field with division name and code, along with
        department name and id, so Departments and Divisions can be
        used with Solr facets but linked to the appropriate code or
        id.  Uses the shortened name of the department.'''
        return '|'.join([self.division_name, self.division_code,
                         self.department_shortname, self.department_id])

    @staticmethod
    def split_department(division_dept_id):
        div, div_code, dept, dept_id = division_dept_id.split('|')
        return {
            'division_name': div,
            'division_code': div_code,
            'department_name': dept,
            'department_id': dept_id,
            }

    @property
    def affiliations(self):
        try:
            profile = self.profile()
        except UserProfile.DoesNotExist:
            return []
        return profile.position_set.all()

    def index_data(self):
        '''Indexing information for this :class:`EsdPerson` instance
        in a format that :meth:`sunburnt.SolrInterface.add` can
        handle.  If this person is internet or directory suppressed
        and does not have a local profile overridding that
        suppression, returns a dictionary with minimal information to
        be indexed.  Otherwise, returns the item itself for
        :mod:`sunburnt` to inspect and index all fields that match
        fields in the Solr schema.

        :returns: dict or :class:`EsdPerson`
        '''
        if self.internet_suppressed or self.directory_suppressed:
            try:
                profile = self.profile()
            except UserProfile.DoesNotExist:
                profile = None

            # if profile does not exist or suppression override is not set,
            # return *minimal* information
            if profile is None or profile and not profile.show_suppressed:
                return  {
                    'id': self.id,
                    'ppid': self.ppid,
                    'record_type': self.record_type,
                    # info required for co-author lookup
                    'username': self.username,
                    'ad_name': self.ad_name,
                    'first_name': self.first_name,
                    'last_name': self.last_name,
                }


        return self

2 个答案:

答案 0 :(得分:0)

使用最新版本的Django正确配置数据库,否则会给出版本更新的错误。

答案 1 :(得分:0)

根据我和DBA所做的调查,看起来Django 1.5处理索引和/或绑定变量的方式与Django 1.3不同(我知道这不是很多帮助或解释)。

DBA添加了三个索引,道歉我没有前两个代码,但它们似乎没有任何影响。他们说的第三个是基于函数的索引就行了。这是代码:

CREATE INDEX "ESD"."CSTM_FBINDX_LOGN8NTWR" ON "ESD"."CSTM"     (TO_NCHAR("LOGN8NTWR_I"))
  PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
  STORAGE(INITIAL 20971520 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT      FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "SHAREDATA" ;

  analyze index ESD.CSTM_FBINDX_LOGN8NTWR validate structure;