Каков наилучший способ доступа к данным в нормализованной схеме базы данных? - PullRequest
0 голосов
/ 08 февраля 2009

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

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

albums
------
aid
name

songs
-----
aid
sid
length

Эта настройка удобна для хранения данных в нормализованном порядке, поскольку альбом может содержать любое количество песен. Однако доступ к данным в интуитивно понятном виде теперь стал намного сложнее. Запрос, который собирает информацию только об одном альбоме, прост, но как получить сразу несколько альбомов за один запрос?

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

aid, sids,      lengths
1,   [1, 2],    [1:04, 5:45]
2,   [3, 4, 5], [3:30, 4:30, 5:30]

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

Мой вопрос: каков наилучший способ доступа к базе данных с такой схемой? Я застрял с несколькими массивами? Должен ли я хранить всю информацию о песне в объекте, а затем эти песни в одном массиве вместо нескольких массивов? Или есть способ добавить произвольное количество столбцов в набор результатов (своего рода бесконечное соединение), чтобы вместить N песен? Я открыт для любых идей о том, как лучше всего получить доступ к данным.

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

Если это имеет какое-то значение, я использую базу данных PostgreSQL вместе с интерфейсом PHP.

Ответы [ 6 ]

3 голосов
/ 08 февраля 2009

Мне трудно понять вашу точку зрения. Что именно вы подразумеваете под "как вы можете захватить несколько альбомов одновременно в одном запросе"? С чем именно у вас трудности?

Интуитивно я бы сказал:

SELECT
  a.aid    album_id,
  a.name   album_name,
  s.sid    song_id,
  s.name   song_name,
  s.length song_length
FROM
  albums a
  INNER JOIN songs s ON a.aid = s.aid
WHERE
  a.aid IN (1, 2, 3)

и

SELECT
  a.aid         album_id,
  a.name        album_name,
  COUNT(s.sid)  count_songs,
  SUM(s.length) sum_length   /* assuming you store an integer seconds value  */
FROM                         /* here, not a string containing '3:18' or such */
  albums a
  INNER JOIN songs s ON a.aid = s.aid
WHERE
  a.aid IN (1, 2, 3)
GROUP BY
  a.aid

В зависимости от того, что вы хотите знать / отображать. Либо вы запрашиваете в базе данных сводную информацию, либо вы сами рассчитываете ее по результату запроса № 1 в своем приложении.

В зависимости от того, сколько данных кешируется в вашем приложении и как долго запросы обрабатывают одну стратегию, может быть быстрее, чем другая. Я бы порекомендовал запросить БД, хотя. БД созданы для такого рода вещей.

2 голосов
/ 09 февраля 2009

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

Ах, теперь я понимаю ваш вопрос. Вы спрашиваете, как лучше всего микрооптимизировать то, что на самом деле не очень дорого для большинства случаев. И решение, с которым вы играете, на самом деле будет значительно менее эффективным, чем «проблема», которую он пытается решить.

Мой совет - присоединиться к таблицам и вернуть нужные вам столбцы. При возврате менее 10000 записей вы не заметите значительного штрафа за время передачи этого имени альбома с каждой записью песни.

Если вы заметили, что он медленно работает в поле, оптимизируйте его. Но имейте в виду, что многие умные люди потратили около 50 лет на то, чтобы быстро найти решение «присоединяйтесь к столам и возвращайте то, что вам нужно». Я сомневаюсь, что вы справитесь с этой стратегией конкатенации / деконкатенации строк.

1 голос
/ 11 февраля 2009

Я согласен с Джейсоном Кестером, поскольку считаю, что на практике это вряд ли будет узким местом в производительности, даже если у вас есть 10 столбцов с повторяющимися данными. Однако, если вы хотите вырезать эти повторяющиеся данные, я предлагаю использовать 2 запроса:

Запрос № 1:

SELECT sid, length     -- And whatever other per-song fields you want
FROM songs
ORDER BY aid

Запрос № 2:

SELECT aid, a.name, COUNT(*)
FROM albums a
JOIN songs s USING (aid)
GROUP BY aid, a.name
ORDER BY aid, a.name

Второй запрос позволяет вам соответствующим образом разбить выходные данные первого запроса на сегменты. Обратите внимание, что это будет работать надежно только в том случае, если вы предполагаете, что между этими двумя запросами в таблицу не будет внесено никаких изменений - в противном случае вам понадобится транзакция с SET TRANSACTION ISOLATION LEVEL SERIALIZABLE.

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

0 голосов
/ 15 февраля 2009

Я бы не стал нарушать твою нормализацию. Оставьте таблицы в покое, а затем используйте следующее для запроса - Как объединить строки строкового поля в запросе группы 'PostgreSQL'?

0 голосов
/ 09 февраля 2009
SELECT aid,GROUP_CONCAT(sid) FROM songs GROUP BY aid; 

+----+-------------------------+
|aid | GROUP_CONCAT(sid)       |
+----+-------------------------+
|  3 | 5,6,7                   |
+----+-------------------------+
0 голосов
/ 08 февраля 2009

Запросы на соединение попросят базу данных собрать таблицы, соответствующие идентификаторам и вернуть одну таблицу. Таким образом, данные могут быть динамически сконфигурированы для текущей задачи, чего не могут делать ненормализованные базы данных.

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