Разбор ЧПУ

09.04.2003 18:39
Информация о рубриках хранится в базе. Но на ее основе генерится php-файл. Примерно такой:

$dir['news']['id']='1';
$dir['news']['name']='новости';
$dir['news/world']['id']='2';
$dir['news/world']['name']='мир';
$dir['news/world/iraq']['id']='3';
$dir['news/world/iraq']['name']='Ирак';

Когда нужно разобрать УРЛ, типа news/world/iraq, он прогоняется через массив $dir 3 раза. После этого получаем id рубрики вместе с id подрубрик и их русские названия. (новости/мир/Ирак). В противном случае пришлось бы делать 3 обращения к БД, а так — ни одного. Так что при загрузке каждой страницы лишних 1-3 обращений к базе… Это некузяво.


Дима, а ты до сих пор считаешь, что это хорошее решение? Может быть, знаешь способ лучше?

Автор ответил:
А чем этот не нравится?
Чтобы разговор был конкретным, я опишу то, что сейчас разрабатываю.

В таблице БД есть набор элементов («статей»). У каждого элемента есть ссылка на родителя (древовидная структура). Каждому элементу можно сопоставить ключевое слово (еще одна таблица id статьи | id ключевого слова).

Я хочу, чтобы на странице стояли ссылки на другие страницы с теми же ключевыми словами, поэтому для каждой такой страницы по id нужно получить его URL (ЧПУ). Для этого можно генерить массив вроде указанного выше.

Далее, любую страницу можно сделать видимой или нет для посетителей. Если вдруг я сделаю невидимым какой-нибудь раздел, ссылка на статью из него со страницы с тем же ключевым словом будет неуместной. Выходит, мне нужно перегенерить вышеупомянутый массив (может быть, частично) каждый раз, когда я меняю «видимость» элементов.

Я собираюсь сделать кеширование каждой страницы, и при обновлении удалять из кеша только те страницы, которые изменились. И тут возникает вопрос, стоит ли вообще в таком случае способом из заметки кешировать пары url-id?

Автор ответил:
Именно для каждой заметки такое использовать, наверное, не надо. Я использую только для рубрик, так как рубрик мало, и меняются они редко. Причем у меня ДВА массива — один для разбора url -> id, второй — для id -> url.

У меня (spectator.ru) сделано так:

Когда надо получить url документа(ов) с помощью какой-то выборки, из базы документов считываются поля url и dir, где url — это «конец урла», то есть самый последний параметр, а dir — это id директории.

Ну и массив dirn (для разбора id -> url), имеет вид

$dirn['71']='technology/software/games';
$dirn['91']='technology/software/games/english_reviews';

После чего $url = $dirn[$dir].$url

Например, spectator.ru/technology/software/games/dice

url — dice [index]
dir — 71 (technology/software/games) [index]

Ну и, естественно, url — это index. Благо, что он короткий.

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

То, что в таком случае нужно два массива — это понятно :)

Да, это хороший способ — в массивах хранить информацию только о рубриках. Ссылки на ключевые слова можно будет расставить, сделав всего один запрос.

Только не совсем понятно, будет ли от этого существенный выигрыш, если страницы и так будут кешироваться?

Автор ответил:
Ну, у меня есть и эта штука и кэширование на всякий случай. Все-таки лишняя оптимизация не помешает, не надо все валить на кэширование.
На nudnik-е я вообще не стал кэширование делать, кстати.
А тогда такой вопрос про R2: как на странице с десятью записями (например, на главной) для каждой записи выводятся ключевые слова? Количество комментариев — понятно, count(if(…)). Но с ключевыми словами в свое время ничего лучше N запросов для каждой записи и кеширования я не придумал :(

Автор ответил:
Ну, чисто теоретически можно сделать так: помимо таблицы связи ключевых слов вида id поста — id ключевого слова можно хранить избыточную информацию в таблице постов. Например, keywords (varchar), а там id ключевых слов в виде «1,3,5». А дальше уже просто проблема преобразования id в названия. Можно разбирать, например, аналогично рубрикам.

В результате вывода десяти записей потребуется всего один запрос к «главной базе».

А уже для выборок «все посты этого ключевого слова» используем таблицу связей.

То есть, грубо говоря, ключевые слова «кэшируются» в основную базу постов.

Похоже, способ с массивами не решит всех проблем с движком.

Вот примерный список того, что нужно сделать при показе страницы (ТЗ?):

1.
а) Разобрать ЧПУ,
б) построить «хлебные крошки»,
в) узнать шаблон.
2. Получить текст.
3. Для рубрики получить подрубрики и заметки в ней, для заметки получить другие заметки в той же рубрике.
4.
а) Получить названия ключевых слов,
б) получить id заметок с ключевыми словами из 4а,
в) преобразование id->URL
5. Комментарии
6. Не забыть про заголовок Last-Modified.

Шаблон, как и «неотображение», должен наследоваться.

Без оптимизации самый критичный по быстродействию и нагрузке — 4 пункт.

Допустим, в массивах с индексом id будут храниться заголовки, полные URL, шаблоны рубрик (решение для пунктов 1, 4в). Тогда на 2, 3, 4а, 4б, 5 уйдет по запросу.

С пунктом 6 не всё так просто. Для этого я обновляю специальное поле у записи/раздела, содержащее время изменения, если на соответствующей странице что-то меняется (текст, ссылки, распределение по разделам). Фокус с массивами не проходит, потому что рубрика может обновиться, а заметка в ней — нет (пример: в рубрике появилась подрубрика).

Не проще ли тогда полный URL кешировать в специально отведенном для этого поле? Я ведь и так обновляю время изменения, а в том же запросе легко можно обновить и полный URL.

Автор ответил:
Так в чем проблемы-то? =) Я же сразу написал, для чего этот способ нужен. Не надо на него все валить.

У меня, кстати, кэш сделан так: если кэш страницы есть (файл найден), то он выдается. Если его нет, то страница генерится, выдается и пишется в кэш.

Соотвественно, при изменении страницы стираем просто ее файл кэша, никакое поле Last-Modified никуда не пишется.

То же самое я сделал у себя в блоге. Только получается, что работа движка (Last-Modifird, If-Modified-Since) зависит от того, включено ли кеширование на сервере. Сейчас хочу отделить эти две функции.

На кеширование нельзя всё валить, на массивы тоже. Надо же на что-то валить :)

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

Офисные шкафы из Европы: офисные шкафы. Метал-ие шкафы стеллажи верстаки. ; выгодно купить женские кожаные сандалии только у нас ; Доска объявлений: б/у товары - медицинская мебель. Наша мебель служит долго. ; Ищешь Верстак - верстаки. Складское оборудование. ; Шины в Екатеринбурге - зимняя резина. Шины. Бесплатная доставка.