Результаты запроса ORM:Массивы и дескриптор результата, заключенный в интерфейс Iterator
-
22-08-2019 - |
Вопрос
Хорошо, вот один для профессионалов:
Вот уже пару лет я работаю над своей собственной реализацией PHP ORM/ActiveRecord, которую я назвал Свинина.dbObject.
Он основан на фильме «Создайте свой собственный сайт с помощью рельсов за 5 минут», который мы все видели пару лет назад.Вы можете делать такие вещи, как:
$clients = dbObject::Search("Client", array("ID > 500"));
или
$client = new Client(218); // fetch row with id 218 from client table
или
$projects = $client->Find('Project');
Это позволит получить одну или несколько строк из базы данных, обернуть их в dbObject и вернуть в один массив или вернуть false, если результатов нет.
Все это прекрасно работало на десятках сайтов и бэкэндов, но теперь мой коллега использует это для создания огромного анализатора журналов, и здесь начинаются проблемы с использованием памяти..
Запросы, которые он выполняет, могут возвращать более 20 000 строк, а может быть, и больше, что, конечно, не очень хорошо, если сразу все помещать в оболочку объекта и возвращать как один массив.
Очевидным решением было бы вернуть объект, реализующий Итератор интерфейс вместо массива.Он не должен мгновенно извлекать все записи из набора результатов, а просто хранить ресурс результата для сгенерированного запроса к базе данных и использовать mysql_fetch_* внутри себя, когда вы перемещаетесь по объекту, как если бы это был массив.
Теперь мы подошли к моему реальному вопросу:Могу ли я без проблем просто это сделать?Могут ли базы данных обрабатывать несколько открытых наборов результатов, смешивать их и хранить в памяти какое-то время?
Например, извлеките 20 объектов, зациклите их, пусть каждый из этих 20 извлекает 5 других, которые, в свою очередь, также извлекают 3 других.Это создаст цикл, в котором в памяти будет храниться несколько различных дескрипторов результатов.
Я знаю, что не могу сериализовать один из этих объектов, но смогу ли я без проблем реализовать это в PHP5, или интерфейсы базы данных вызовут у меня проблемы?
Решение
Это зависит от того, какую базу данных вы используете и конфигурации вашей базы данных.
Для MySQL вам необходимо убедиться, что вы используете буферизованные запросы.В PDO вы устанавливаете это так:
$myPdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
Это означает, что все данные будут отправлены клиенту (это не то же самое, что получение всех этих данных в PHP).
Другая (вероятно, худшая) альтернатива — открывать новое соединение с базой данных всякий раз, когда вы обнаруживаете, что выполняется запрос с открытым набором результатов.
Нормальный mysql_query()
использует буферизованный запрос, поэтому он будет работать с несколькими наборами результатов.