Оптимизированное решение для хранения порядка строк в базе данных - PullRequest
0 голосов
/ 29 сентября 2010

У меня есть модель данных в Doctrine / symfony.У меня есть «Курс», в котором много «Урока».Для каждого урока мне нужно рассчитать порядок (по дате) появления урока.Например, курс «Java для начинающих» может состоять из 10 уроков в октябре, мне нужно получить порядок этих уроков, чтобы первый назывался «Java для начинающих 1» и т. Д.

В настоящее время у меня естьметод getTitle () в моей модели урока, который запрашивает базу данных, чтобы установить число.Это отлично работает.Однако, когда на экране 400 уроков (это типичный вариант использования), это приводит к 400+ запросам.

Я читал о поведении доктрины и, насколько я понимаю, я мог бы добавлять поведение для каждого разаУрок добавлен, отредактирован или удален. Я могу пересчитать все порядковые номера - сохранить их в базе данных.Однако я не могу заставить это работать эффективно.

Есть ли более эффективный метод, чем тот, который я упомянул?

Cheers,

Matt

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;

И этот код находится в модели урока как функция.Он вычисляет порядковый номер данного урока и возвращает его как целое число.Этот метод вызывается более 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 голосов
/ 29 сентября 2010

Изменить:

Вам не хватает памяти, потому что вы съели тонны памяти со всеми этими объектами. Вы должны попробовать дозировать группы по 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();

Таким образом, информация о Курсе и Уроке сводится к одному запросу, и Курс будет гидратирован вместе с Уроком.

Это, конечно, ничего не делает для вашего порядкового номера. Это на самом деле другая проблема, и я думаю, что лучше всего было бы использовать для этого поведение, как вы сами предложили. Если вы хотите опубликовать свой код поведения и описание проблемы, я уверен, что мы можем помочь вам с этим

...