еще раз многоязычность (в бд)

  • Автор темы Автор темы Slastik
  • Дата начала Дата начала

Slastik

Новичок
многоязычность (в бд)

Прошу не отсылать в поиск, 2 часа вычитывал темы по запросам многоязычность и мультиязычность

вопрос следующий как организовать архитектуру хранения в базе

из поиска по форуму и факу выделил два приемлимых варианта

1. Согласно http://phpclub.ru/faq/multilang - архитектура
table1
news_id
news_start

table2
news_id – уникальный номер новости из первой таблицы
news_lang – уникальный двухбуквенный идентификатор языковых данных
news_subject – тема (заголовок) новости

2. Согласно сообщению от Simm
http://phpclub.ru/talk/showthread.php?postid=477658#post477658
table1
id lang_id first_id some_fields
где id - id записи
lang_id - id языка записи
first_id - id первой помещённой в таблицу записи на эту тему на каком-то языке (у первой записи first_id=id)
some_fields - остальные столбцы таблицы

Чаще ссылаются на вариант 1.

В своем приложении я стал использовать его

Но вот какие минусы я вижу.
1. Количество таблиц практически удвоилось
2. При каждой выборке данных необходимо использовать join что скажется в дальнейшем на быстродействие, так как мой проект предпологает высокую нагрузку, кроме того при join происходит filesort (например при сортировке по дате) которого никак нельзя избежать при такой архитектуре. Что есть опять же не хорошо с точки зрения нагрузки.

Например запрос который не удается оптимизировать при такой структуре

SELECT `articles`.`id`, `articles`.`date_create`, `articles_txt`.`title` FROM `articles`
INNER JOIN `articles_txt` ON articles_txt.article_id = articles.id WHERE (is_active = '1') AND (articles.rubric_id = '1') AND (lang_id = 1) ORDER BY `date_create` DESC LIMIT 2

из за обращений к lang_id что лежит в другой таблице

Вариант два позволяет сделать выборки чисто по индексу. Но предпологает дублирование не уникальных данных.

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

Спасибо
 
нужна всего одна таблица для этого раздела к примеру новостей, т.е. в ней должна лежать:
1. Инфа по новости
2. id-шки к второстепенной инфе (к примеру для названия языка)
и для целостности не забудь foreign key :)
 
Автор оригинала: zerkms
конечно же идёт в условие объединения таблиц
перенеси, затем структуры + EXPLAIN в студию
дамп, запрос и результат ниже. При другом расположении индексов всплывает еще и temporary
Насколько я понимаю то избавится от filesort при таких запросах будет не возможно принципиально из за того что в where идут
условия из обеих таблиц, верно?

PHP:
CREATE TABLE IF NOT EXISTS `articles_loc_test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `article_id` int(11) NOT NULL,
  `lang_id` smallint(6) NOT NULL,
  `title` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `article_id_2` (`article_id`,`lang_id`),
  KEY `article_id` (`article_id`),
  KEY `lang_id` (`lang_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;

CREATE TABLE IF NOT EXISTS `articles_test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `date_create` datetime NOT NULL,
  `is_active` enum('0','1') NOT NULL DEFAULT '0',
  `rubric_id` int(11) NOT NULL,
  `img` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `is_active` (`is_active`,`rubric_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

explain SELECT `articles_test`.`id`, `articles_loc_test`.`title` FROM `articles_test`
 INNER JOIN `articles_loc_test` ON articles_loc_test.article_id = articles_test.id WHERE (articles_test.rubric_id = '1') AND (lang_id = 1) ORDER BY `articles_test`.`date_create` DESC LIMIT 2

результат
Array
(
    [0] => Array
        (
            [id] => 1
            [select_type] => SIMPLE
            [table] => articles_test
            [type] => ALL
            [possible_keys] => PRIMARY
            [key] => 
            [key_len] => 
            [ref] => 
            [rows] => 6
            [Extra] => Using where; Using temporary; Using filesort
        )

    [1] => Array
        (
            [id] => 1
            [select_type] => SIMPLE
            [table] => articles_loc_test
            [type] => ALL
            [possible_keys] => rubric_id
            [key] => 
            [key_len] => 
            [ref] => 
            [rows] => 9
            [Extra] => Using where; Using join buffer
        )

)
 
Slastik
я же попросил идентифиактор языка - в условие объединения (ON)
 
zerkms я что то тебя не понимаю , каким образом я туда могу внести lang_id. Таблица articles не предпологает нахождения в ней языка. Там на каждую статью по одной записи.
 
zerkmsа разве есть какая-то разница, где указывать lang_id - в on или where?
 
zerkms мой запрос выбирает статьи по определенной рубрике на указанном языке отсортированные по дате.. может ты немного не так меня понял..
 
berkut
неужели оптимизатор такой умный, что всё сам сделает?

Slastik
INNER JOIN `articles_loc_test` ON articles_loc_test.article_id = articles_test.id AND lang_id

сделай так и покажи эксплейн?

KEY `lang_id` (`lang_id`) можешь убрать, смысла в нём (в этом запросе конкретно) нету
 
Автор оригинала: zerkms
berkut
неужели оптимизатор такой умный, что всё сам сделает?

Slastik
INNER JOIN `articles_loc_test` ON articles_loc_test.article_id = articles_test.id AND lang_id

сделай так и покажи эксплейн?

KEY `lang_id` (`lang_id`) можешь убрать, смысла в нём (в этом запросе конкретно) нету
PHP:
 Array
(
    [0] => Array
        (
            [id] => 1
            [select_type] => SIMPLE
            [table] => articles
            [type] => ref
            [possible_keys] => PRIMARY,rubric_id,rubric_id_2
            [key] => rubric_id_2
            [key_len] => 3
            [ref] => const
            [rows] => 3
            [Extra] => Using where; Using index
        )

    [1] => Array
        (
            [id] => 1
            [select_type] => SIMPLE
            [table] => articles_txt
            [type] => eq_ref
            [possible_keys] => article_id,article_id_2,lang_id
            [key] => article_id
            [key_len] => 6
            [ref] => prometr.articles.id,const
            [rows] => 1
            [Extra] => Using where
        )

)

Другое дело :) zerkms жжошь :) А что значит AND lang_id в мануале я что то внятно не могу прочесть этот момент.

-~{}~ 03.07.08 18:04:

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

-~{}~ 03.07.08 18:06:

The conditional_expr used with ON is any conditional expression of the form that can be used in a WHERE clause. Generally, you should use the ON clause for conditions that specify how to join tables, and the WHERE clause to restrict which rows you want in the result set.

из мана, видимо тут случай Not Generally?
 
просто ты часть условия объединения (логика запроса, не оптимизация), поместил в WHERE, где оно быть в принципе не могло... из-за этого у тебя вся схема запроса расползлась...
 
почему lang_id быть впринципе там не могло? Поясни последнюю фразу плз. Мануал не рекомендует писать where условия в On.
Правда не понятно почему :)
 
articles_test - инфа, не зависящая от языка
articles_loc_test - инфа, зависящая от языка

т.о. конкретный экземпляр новости определяется по паре id + lang_id. это и есть логика, согласной которой ты производишь объединение таблиц (поэтому lang_id и входит в ON, наряду с id)

подробнее объяснить не могу, имхо это очевидно. не?
 
Slastik
НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ
 
Сверху