优化的解决方案,用于存储数据库中行的顺序

时间:2010-09-29 14:20:48

标签: symfony1 doctrine

我在Doctrine / symfony中有一个数据模型。我有一个'课程',有许多'课程'。对于每节课,我需要计算课程出现的顺序(按日期)。例如,“初学者的Java课程”可能在10月份有10节课,我需要检索这些课程的顺序,以便第一个被称为“Java for beginners 1”等。

目前,我的Lesson模型中有一个getTitle()方法,用于查询数据库以建立数字。这很好用。但是,当屏幕上有400个课程时(这是一个典型的用例),它会产生400多个查询。

我已经阅读了有关教条行为的内容,据我了解,我可以在每次添加,编辑或删除课程时添加一个行为我可以重新计算所有序列号 - 将它们存储在数据库中。但是,我不能让它有效地工作。

有没有比我提到的方法更有效的方法?

干杯,

马特

Doctrine_Query::create()->
        from('Lesson l')->
        leftJoin('l.Course c')->
        leftJoin('l.Teacher t')->
        leftJoin('l.Students sl')->
        andWhere('l.date BETWEEN ? AND ?', array(date('Y-m-d', $start_date), date('Y-m-d', $end_date)))->
        orderBy('l.date, l.time');

以上代码会返回我的所有课程信息(除了课程编号)。

Doctrine_Query::create()
                ->select('COUNT(l.id) as count')
                ->from('Lesson l')
                ->leftJoin('l.Course c')
                ->where('c.id = ?', $this->course_id)
                ->andWhere('TIMESTAMP(l.date, l.time) < ?', $this->date . ' ' . $this->time)
                ->orderBy('l.date, l.time');
    $lessons = $q->fetchOne();
    return $lessons->count + 1;

此代码作为函数在Lesson模型中。它计算给定课程的序列号并将其作为整数返回。这是被调用400次以上的方法。我尝试将其作为子查询添加到第一个查询中,但没有成功。

行为代码

public function postInsert(Doctrine_Event $event) {
    $invoker = $event->getInvoker();
    $table = Doctrine::getTable('Lesson');

    // Course query
    $cq = Doctrine::getTable('Lesson')->createQuery();
    $cq->select('COUNT(l.id) as count')
            ->from('Lesson l')
            ->leftJoin('l.Course c')
            ->where('c.id = ?', $invoker->Course->id)
            ->andWhere('TIMESTAMP(l.date, l.time) < ?', $invoker->date . ' ' . $invoker->time)
            ->orderBy('l.date, l.time');
    $lessons = $cq->fetchOne();

    $q = $table->createQuery();

    $q->update()->
            set('sequence_number', $lessons->count + 1)->
            where('id = ?', $invoker->id)->
            execute();
}

这里显而易见的问题是它只更新调用的课程。如果一个课程更新其序列,则所有课程都应更新其序列号。但是,当我尝试从我的灯具填充数据库时,上面的代码会导致内存问题(大约5000课,它在~1500失败)。

1 个答案:

答案 0 :(得分:0)

编辑:

因为你吃掉所有这些物品的大量内存,你的内存耗尽。您应该尝试以1000个为一组进行批处理(因为您在~1500时失败)。

您可以做的另一件事是不直接将侦听器/行为放在模型上,而是创建一个postTransactionCommit侦听器。在此侦听器中,您可以检查lesson表中的任何记录是否是提交的一部分,然后以正确的顺序更新它们。


编辑:

所以根据我们的评论......让我们走向另一个方向:

Doctrine_Core::getTable('Course')->createQuery('c')
  ->leftJoin('l.Lesson')
  ->orderBy('l.date_column')
  ->execute();

通常,为了避免额外的查询,您将在查询中执行连接,这样您就不会有额外的费用。例如:

Doctrine_Core::getTable('Lesson')->createQuery('l')
  ->leftJoin('l.Course')
  ->orderBy('l.date_column')
  ->execute();

这样,课程和课程信息将在一个查询中显示,课程将与课程一起保持水分。

这当然对您的序列号没有任何作用。这真的是一个不同的问题,我认为最好的办法就是按照你自己的建议使用一种行为。如果您想发布行为代码和问题描述,我相信我们可以帮助您解决问题