PHP / MySQL ООП: загрузка сложных объектов из SQL - PullRequest
8 голосов
/ 29 августа 2009

Итак, я работаю над проектом для риэлтора. У меня есть следующие объекты / MySQL таблицы в моем дизайне:

Complexes
Units
Amenities
Pictures
Links
Documents
Events
Agents

Это отношения между вышеуказанными объектами.

Complexes have a single Agent.
Complexes have multiple Units, Amenities, Pictures, Links, Documents, and Events.
Units have multiple Pictures, Links, and Documents.

Удобства, рисунки, ссылки, документы и события имеют необходимые внешние ключи в базе данных, чтобы указать, к какому объекту / комплексу они принадлежат.

Мне нужно загрузить необходимые объекты из базы данных в PHP, чтобы я мог использовать их в своем проекте.

Если я попытаюсь выбрать все данные из таблицы в 1 запросе, используя СЛЕВОЕ СОЕДИНЕНИЕ, я получу по крайней мере (количество ссылок) * (количество изображений) * (количество документов) строк для каждого уникального Блок. Добавьте к этому удобства и события, и я получу все эти * # удобства * # событий для каждого комплекса ... Не уверен, что я хочу попытаться загрузить это в объект в PHP.

Другая возможность для каждого комплекса / блока - выполнить 1 отдельную инструкцию SQL для ссылок, изображений, документов, событий и удобств

У меня следующие вопросы:

Если я правильно проиндексировал все свои таблицы, действительно ДЕЙСТВИТЕЛЬНО плохая идея выполнить 3-5 дополнительных запросов для каждого комплекса / единицы?

Если нет, то как еще я могу получить данные, которые мне нужно загрузить в объект PHP. В идеале у меня должен быть объект для юнитов:

Unit Object
(
    [id]
    [mls_number]
    [type]
    [retail_price]
    [investor_price]
    [quantity]
    [beds]
    [baths]
    [square_feet]
    [description]
    [featured]
    [year_built]
    [has_garage]
    [stories]
    [other_features]
    [investor_notes]
    [tour_link]
    [complex] => Complex Object
        (
            [id]
            [name]
            [description]
            etc.
        )
    [agent] => Agent Object
        (
            [id]
            [first_name]
            [last_name]
            [email]
            [phone]
            [phone2] 
            etc.

        )
    [pictures] => Array
        (
            [1] => Picture Object
                (
                )
        )
    [links] => Array
        (
            [1] => Link Object
                (
                )
        )
    [documents] => Array
        (
            [1] => Document Object
                (
                )
        )    
)

Мне ВСЕГДА не нужна ВСЕ эта информация, иногда мне нужен только первичный ключ комплекса, иногда мне нужен только первичный ключ агента и т. Д. Но я решил, что правильным способом сделать это будет загружать весь объект каждый раз, когда я его создаю.

Я много исследовал OO PHP, но в большинстве (читать все) онлайн-примеры используется только 1 таблица. Это, очевидно, не помогает, так как проект, над которым я работаю, имеет много сложных отношений. Есть идеи? Я полностью не в курсе?

Спасибо

[UPDATE]

С другой стороны, обычно на внешнем интерфейсе, который увидят все, мне понадобится ВСЕ данные. Например, когда кому-то нужна информация о конкретном комплексе, мне нужно отобразить все единицы, принадлежащие этому комплексу, все изображения, документы, ссылки, события для комплекса, а также все изображения, документы и ссылки для единицы.

Чего я хотел избежать, так это во время загрузки одной страницы выполнить один запрос, чтобы получить комплекс, который мне нужен. Затем другой запрос, чтобы получить 20 единиц, связанных с комплексом. Затем для каждого из 20 блоков, выполняя запрос для изображения, другой для документов, другой для ссылок и т. Д. Я хотел получить их все сразу, с одним обходом базы данных.

[РЕДАКТИРОВАТЬ 2] Также обратите внимание, что запросы на выбор изображений, документов, ссылок, событий и агента из базы данных довольно просты. Просто базовый SELECT [список столбцов] FROM [таблица] WHERE [primary_key] = [значение] со случайным INNER JOIN. Я не делаю никаких сложных вычислений или подзапросов, я просто делаю простые вещи.

[ЭТАЛОН]Поэтому, прочитав все ответы на мой вопрос, я решил провести тест на то, что решил сделать. Что я делаю, так это загружаю все нужные мне устройства. Затем, когда мне нужно отобразить картинки, документ, бла-бла, я загружаю их в это время. Я создал 30 000 тестовых блоков, в каждом из которых 100 изображений, 100 документов и 100 ссылок. Затем я загрузил определенное количество единиц (я начал с 1000, затем 100, затем более реалистичных 10), прошел через них, затем загрузил все картинки, документы и ссылки, связанные с единицей. С 1000 единиц это заняло примерно 30 секунд. С 100 единицами это заняло около 3 секунд. С 10 юнитами это заняло около 0,5 секунды. Было много расхождений с результатами. Иногда с 10 единицами это может занять 0,1 секунды. Тогда это займет 0,8. Тогда возможно .5. Тогда 0,78. Это было действительно повсюду. Тем не менее, казалось, в среднем около половины секунды. В действительности, однако, мне может понадобиться только 6 блоков одновременно, и у каждого из них может быть только 10 изображений, 5 ссылок и 5 документов, связанных с ними ... поэтому я думаю, что подход "захватывать данные, когда вам это нужно" лучшая ставка в такой ситуации. Однако если вам нужно получить все эти данные одновременно, было бы целесообразно придумать единый оператор SQL для загрузки всех необходимых вам данных, поэтому вы выполняете циклический просмотр данных только один раз (6700 единиц за раз занимали 217 секунд). в то время как полные 30000 заставили PHP исчерпать память).

Ответы [ 5 ]

4 голосов
/ 29 августа 2009

Если я правильно проиндексировал все свои таблицы, действительно ДЕЙСТВИТЕЛЬНО плохая идея выполнить 3-5 дополнительных запросов для каждого комплекса / единицы?

Короче, нет. Для каждой из связанных таблиц вам, вероятно, следует выполнить отдельный запрос. Это то, что делает большинство систем ORM (объектно-реляционное отображение / моделирование).

Если производительность действительно является проблемой (и, исходя из того, что вы сказали, не будет), то вы можете рассмотреть вопрос о кэшировании результатов, используя что-то вроде APC, memcache или Xcache.

0 голосов
/ 29 августа 2009

Если вы хотите «сохранить» объекты, то есть кэшировать их, просто загрузите их в массив PHP и сериализуйте его. Затем вы можете сохранить его обратно в базу данных, в memcache или в любом другом месте. Прикрепив к нему метку, вы сможете получить ее и включить временную метку, чтобы вы знали, сколько ей лет (т.е. необходимо обновить).

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

0 голосов
/ 29 августа 2009

Мне пришлось обратиться к этой проблеме некоторое время назад, когда я создал свой собственный MVC-фреймворк в качестве эксперимента. Чтобы ограничить слои данных, загружаемых из БД, я передал целое число в конструктор. Каждый конструктор будет уменьшать это целое число перед тем, как передать его конструкторам объектов, которые он создал. Когда он достигнет 0, никакие дополнительные объекты не будут созданы. В основном это означало, что переданное int было количеством загруженных слоев.

Итак, если бы я хотел только атрибут объекта объекта, я бы сделал это:

$myUnit = new Unit($unitId,1);
0 голосов
/ 29 августа 2009

Может быть, вам стоит подумать о том, чтобы разбить это.

Когда вы инициируете свой объект, получите только те детали, которые вам нужны для функционирования этого объекта. Если и когда вам нужно больше деталей, тогда иди и получить их. Вы распределяете нагрузку и обработку таким образом: объект получает только нагрузку и обработку, необходимые для его функционирования, а когда требуется больше, он получает его.

Итак, в вашем примере - сначала создайте комплекс. Когда вам нужно получить доступ к устройству, затем создайте его, когда вам нужен агент, затем получите этого агента и т. Д.

$complexDetails = array('id' => $id, etc);
$complexUnits = array();
.........
$complexUnits[] = new unit();
.........
$complexDetails['agent'] = new Agent();
0 голосов
/ 29 августа 2009

смысл ORM не в том, чтобы загружать целиком объекты каждый раз. смысл в том, чтобы сделать ваше приложение простым и прозрачным для доступа к объекту.

при этом, если вам нужен объект объекта, загрузите объект объекта и только объект объекта. если вам нужен объект агента, загружайте его тогда, когда он вам нужен, а не когда вы загружаете объект объекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...