воскресенье, 20 октября 2013 г.

Хранение связанных записей в одной таблице.

Пусть у нас есть подчиненные записи.

Ну, например, продукт, и связанные с ним продукты.
В одной таблице

Как люди хранят такое?
Ну например добавляют поле parent в таблицу, и заполняют там id родителя.

Получается такая табличка
create table products (id int, name varchar(10), parent int id);
Какие у нее плюсы? Она нормализована, по числовому полю parent можно построить индекс, и эффективно выбирать нужные записи.

Ну, т.е. запрос дайте мне подчиненные записи этой, выглядит как

select id from products where parent=$id

Как выбрать подчиненные записи к этому списку?

select id from products where parent in (...)

Как выбрать подчиненные записи к выборке с таким то условием


select ... from products p1 inner join products p2 on p1.parent=p2.id where p2.foo=bar and p2.bar=foo


Что может быть проще и для кодера и для субд?

Всегда готовый результат одним запросом с отличным планом.

Хорошо, переходим на темную сторону.

Открываем код движка phpshop
Создание интернет-магазина - это наша профессия и мы готовы поделиться с вами опытом, накопленным за 10 лет работы.

Давайте посмотрим, как накопленный десятилетний опыт, помогает в решении таких примитивных задач.

Они действительно добавили поле parent,  тип varchar(255) , но пишут туда id подчиненных записей к этой, через запятую.

Вероятно программисты были заняты, и решение поручили офис менеджеру.

Велика ли разница? Разница колоссальна.

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

А какие плюсы? Никаких.

Как теперь выглядит запрос ?  эмм, а никак. Теперь надо данные тащить на клиента сначала, там декодировать и потом делать новые запросы.

Т.е. вместо  одного запроса получили вложенные циклы с запросами.

Сначала отбираем главные продукты,
 select id from products where bar=foo and foo=bar

затем качаем записи на клиента, while {$row= ...}
затем внутри цикла парсим (split) записи, делаем еще один запрос для подчиненых (!) а то и несколько если логика сложнее внутри цикла.


Это даже не идиотизм, я не знаю как это назвать.

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

И следующий запрос опять исполнит вся пляски сначала.