Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Деревья в MySQL и URI

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (2): [1] 2 »   

> Описание: Есть ли способ хранить URI
Hapson
Отправлено: 25 Апреля, 2014 - 19:46:59
Post Id



Посетитель


Покинул форум
Сообщений всего: 356
Дата рег-ции: Июнь 2013  
Откуда: Ставропольский край


Помог: 10 раз(а)

[+]


Мучаюсь уже который день с проблемой.
Суть такова:
в базе хранятся категории и статьи. Статьи хранятся в одной таблице с указанием ID родительской категории. Для хранения категорий использую таблицу связей + список смежностей.
Вот таблицы:

данные категорий (таблица 'cat')
CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. id      id_parent       alias
  3. 21      NULL    blog
  4. 22      21      vasa
  5. 23      21      peta
  6.  

связи категорий (таблица 'cat_tree')
CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. parent  children
  3. 21      21
  4. 21      22
  5. 21      23
  6. 22      22
  7. 23      23
  8.  

статьи (таблица 'art')
CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. id      id_cat  alias   title
  3. 1       22      remont  Вася ремонт
  4. 2       23      remont  Петя ремонт
  5.  


Проблема: одинаковый alias в разных категориях
В разных категориях могут быть статьи с одинаковыми alias. А так как при такой структуре нигде не хранится полный путь к статье, то это увеличивает кол-во запросов при поиске пути.
К примеру у нас запросили URL:
CODE (htmlphp):
скопировать код в буфер обмена
  1. http://site.ru/blog/vasa/remont

В базе у нас две статьи "remont".
Что делаем?
Выбираем все статьи из таблицы "art" у которых "alias" = "remont"
PHP:
скопировать код в буфер обмена
  1.  
  2. $sql = "select * from `art` where `alias` = 'remont'";
  3. $id_cats = selectTable($sql);
  4. var_dump($id_cats); echo '<hr />';
  5.  

Получаем
CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. array (size=2)
  3.   0 =>
  4.     array (size=4)
  5.       'id' => string '1' (length=1)
  6.       'id_cat' => string '22' (length=2)
  7.       'alias' => string 'remont' (length=6)
  8.       'title' => string 'Вася ремонт' (length=21)
  9.   1 =>
  10.     array (size=4)
  11.       'id' => string '2' (length=1)
  12.       'id_cat' => string '23' (length=2)
  13.       'alias' => string 'remont' (length=6)
  14.       'title' => string 'Петя ремонт' (length=21)
  15.  

Две статьи из разных категорий с одинаковыми "alias". Теперь нужно найти полные пути для этих статей, чтобы потом сравнить их с тем, что у нас запросили. А запросили у нас
Пути нужно выбирать поочередно, для каждого путя запрос
PHP:
скопировать код в буфер обмена
  1.  
  2. foreach($id_cats as $k => $v){
  3.         $sql = "
  4.                 select
  5.                         `cat`.`alias`
  6.                 from
  7.                         `cat`, `cat_tree`
  8.                 where
  9.                         `cat`.`id` = `cat_tree`.`parent`
  10.                 and
  11.                         `cat_tree`.`children` = {?}
  12.                 ";
  13.         $arr_path = selectTable($sql, array($v['id_cat']));
  14.         $uri = '';
  15.         foreach($arr_path as $v){
  16.                 $uri .= $v['alias'] ."/";
  17.         }
  18.         $id_cats[$k]['uri'] = $uri .'remont';
  19. }
  20. var_dump($id_cats);
  21.  

Получаем
CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. array (size=2)
  3.   0 =>
  4.     array (size=5)
  5.       'id' => string '1' (length=1)
  6.       'id_cat' => string '22' (length=2)
  7.       'alias' => string 'remont' (length=6)
  8.       'title' => string 'Вася ремонт' (length=21)
  9.       'uri' => string 'blog/vasa/remont' (length=16)
  10.   1 =>
  11.     array (size=5)
  12.       'id' => string '2' (length=1)
  13.       'id_cat' => string '23' (length=2)
  14.       'alias' => string 'remont' (length=6)
  15.       'title' => string 'Петя ремонт' (length=21)
  16.       'uri' => string 'blog/peta/remont' (length=16)
  17.  

И вот теперь мы можем отдать ту статью, у которой совпал URI.
Итого 3 запроса. Но если в базе будет не 2, а 20 статей с одинаковыми "alias" в разных категориях?
Можно конечно в цикле сразу проверять - совпал URI или нет. Но велика вероятность, что он совпадет на 15, 18... запросе.

Короче некошерно как-то... Все прекрасно, если в таблице статей есть поле URI. Но такое поле иметь нельзя. В случае переименования категории, все данные в поле URI станут бесполезными.

Есть ли способ хранить URI статьи, но так чтобы не пришлось делать сложных и глобальных обновлений и поправок в случае переименования категории, в которой уже есть 100500 статей?


-----
ПЫХ тут - ходи туда, прежде чем писать сюда (толку больше будет)
 
 Top
T1grOK
Отправлено: 25 Апреля, 2014 - 20:55:38
Post Id



Частый гость


Покинул форум
Сообщений всего: 129
Дата рег-ции: Июнь 2013  


Помог: 7 раз(а)




Hapson пишет:
Все прекрасно, если в таблице статей есть поле URI. Но такое поле иметь нельзя. В случае переименования категории, все данные в поле URI станут бесполезными.

Ну так всех потомков тоже обработать...


-----
Mysql, Postgresql, Redis, Memcached, Unit Testing, CI, Kohana, Yii, Phalcon, Zend Framework, Joomla, Open Cart, Ymaps, VK Api
 
 Top
Hapson
Отправлено: 25 Апреля, 2014 - 21:01:35
Post Id



Посетитель


Покинул форум
Сообщений всего: 356
Дата рег-ции: Июнь 2013  
Откуда: Ставропольский край


Помог: 10 раз(а)

[+]


T1grOK
есть категория "blog", в ней есть категория "vasa". В категории "vasa" есть 100 статей. URI получатся такими:
/blog/vasa/art_1
/blog/vasa/art_2
...
/blog/vasa/art_N

И вот я хочу переименовать "vasa" в "vasya". Итого мне нужно будет перебрать и обновить все 100 URI. Так нельзя.
Это можно сделать, но не нужно так.


-----
ПЫХ тут - ходи туда, прежде чем писать сюда (толку больше будет)
 
 Top
T1grOK
Отправлено: 25 Апреля, 2014 - 21:58:45
Post Id



Частый гость


Покинул форум
Сообщений всего: 129
Дата рег-ции: Июнь 2013  


Помог: 7 раз(а)




Hapson пишет:
И вот я хочу переименовать "vasa" в "vasya". Итого мне нужно будет перебрать и обновить все 100 URI. Так нельзя.

Жесть) Волшебным образом задача не разрешится. Я полагаю, приоритет будет на чтение, чем на запись. Когда-никогда будет изменено название какого-то родителя - подумаешь обновить 100 записей...


-----
Mysql, Postgresql, Redis, Memcached, Unit Testing, CI, Kohana, Yii, Phalcon, Zend Framework, Joomla, Open Cart, Ymaps, VK Api
 
 Top
Hapson
Отправлено: 25 Апреля, 2014 - 22:13:56
Post Id



Посетитель


Покинул форум
Сообщений всего: 356
Дата рег-ции: Июнь 2013  
Откуда: Ставропольский край


Помог: 10 раз(а)

[+]


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


-----
ПЫХ тут - ходи туда, прежде чем писать сюда (толку больше будет)
 
 Top
T1grOK
Отправлено: 26 Апреля, 2014 - 08:41:52
Post Id



Частый гость


Покинул форум
Сообщений всего: 129
Дата рег-ции: Июнь 2013  


Помог: 7 раз(а)




Hapson пишет:
Если хранить полные пути статей, составленные из алиасов категорий, то это огромное дублирование.

И что? Вы решитесь то ли идти более "нормализованным" путем и делать N запросов, или более "денормализованным" - получать избыточность и на N запросов меньше.


-----
Mysql, Postgresql, Redis, Memcached, Unit Testing, CI, Kohana, Yii, Phalcon, Zend Framework, Joomla, Open Cart, Ymaps, VK Api
 
 Top
Hapson
Отправлено: 26 Апреля, 2014 - 14:04:22
Post Id



Посетитель


Покинул форум
Сообщений всего: 356
Дата рег-ции: Июнь 2013  
Откуда: Ставропольский край


Помог: 10 раз(а)

[+]


T1grOK
Ну да, тут вероятно придется выбирать и чем-то жертвовать


-----
ПЫХ тут - ходи туда, прежде чем писать сюда (толку больше будет)
 
 Top
LIME
Отправлено: 26 Апреля, 2014 - 14:34:23
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




Hapson не вникал особо в проблему но считаю нужным сказать))
есть даже такой термин "умышленная денормализация"
 
 Top
Hapson
Отправлено: 26 Апреля, 2014 - 14:44:27
Post Id



Посетитель


Покинул форум
Сообщений всего: 356
Дата рег-ции: Июнь 2013  
Откуда: Ставропольский край


Помог: 10 раз(а)

[+]


LIME
LIME пишет:
есть даже такой термин "умышленная денормализация"

знаю, знаю...
LIME пишет:
не вникал особо в проблему но считаю нужным сказать))

Суть проста - у каждой категории есть алиас - транслит от названия категории.
Путь к каждой статье состоит из алиасов категорий-родителей и алиаса самой статьи.
Проблема в том, как хранить этот путь. Тупо делать поле uri для каждой категории или статьи - это не то. Будут проблемы потом при переименовании категорий, при переносе статей между категориями...
Если не хранить этот путь, то для поиска статьи может потребоваться много запросов, учитывая тот факт, что в разных категориях могут быть статьи с одинаковым полем алиас.


-----
ПЫХ тут - ходи туда, прежде чем писать сюда (толку больше будет)
 
 Top
LIME
Отправлено: 26 Апреля, 2014 - 14:51:35
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




навскидку решение
всетаки хранить путь (практически matherialized path)
написать метод для изменения алиаса который будет пробегать всех детей и менять путь и использовать только его для изменений алиасов
(Добавление)
исходим из того что изменения не происходят часто
потому не важно сколько запросов потребует изменение гораздо важнее скорость выборки
 
 Top
Hapson
Отправлено: 26 Апреля, 2014 - 14:54:32
Post Id



Посетитель


Покинул форум
Сообщений всего: 356
Дата рег-ции: Июнь 2013  
Откуда: Ставропольский край


Помог: 10 раз(а)

[+]


Простейшее решение есть - добавлять id статьи в ее alias.
типа:
CODE (SQL):
скопировать код в буфер обмена
  1.  
  2. SET @alias = "new-article";
  3. INSERT INTO `art` (`id_cat`, `alias`, `title`) VALUES (22, @alias, "Новая статья");
  4. SET @lid = last_insert_id();
  5. UPDATE `art` SET `alias` = CONCAT(@lid, "_", `alias`) WHERE `id_art` = @lid;
  6.  


Мне лично id в адресной строке никак не помешает. Поисковикам тоже.
Но вдруг я потом буду какому-то дяде делать сайт, и он мне скажет - что это за цифры в адресной строке, надо убрать, некрасиво.
(Добавление)
LIME пишет:
написать метод для изменения алиаса который будет пробегать всех детей и менять путь и использовать только его для изменений алиасов

Видимо только так...


-----
ПЫХ тут - ходи туда, прежде чем писать сюда (толку больше будет)
 
 Top
LIME
Отправлено: 26 Апреля, 2014 - 14:56:19
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




поисковикам не мешает но и не помогает
лучше отразить тематику страницы в ссылке
 
 Top
T1grOK
Отправлено: 26 Апреля, 2014 - 14:56:28
Post Id



Частый гость


Покинул форум
Сообщений всего: 129
Дата рег-ции: Июнь 2013  


Помог: 7 раз(а)




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

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


-----
Mysql, Postgresql, Redis, Memcached, Unit Testing, CI, Kohana, Yii, Phalcon, Zend Framework, Joomla, Open Cart, Ymaps, VK Api
 
 Top
LIME
Отправлено: 26 Апреля, 2014 - 14:58:21
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




Hapson пишет:
Видимо только так...
не понимаю что тебя смущает
1 раз цикл запросов при редакции или много раз гемор при выборке
(Добавление)
T1grOK nested sets тут при чем?
 
 Top
Hapson
Отправлено: 26 Апреля, 2014 - 20:05:42
Post Id



Посетитель


Покинул форум
Сообщений всего: 356
Дата рег-ции: Июнь 2013  
Откуда: Ставропольский край


Помог: 10 раз(а)

[+]


LIME
LIME пишет:
не понимаю что тебя смущает

Смущала чрезмерная денормализация.
Но это будет оправдано моментальными выборками статей.
А если лепить ID в начало или конец алиаса, то еще быстрее будет.


-----
ПЫХ тут - ходи туда, прежде чем писать сюда (толку больше будет)
 
 Top
Страниц (2): [1] 2 »
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Вопросы новичков »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB