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

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 что лежит в другой таблице

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

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

Спасибо
 

nirex

Новичок
нужна всего одна таблица для этого раздела к примеру новостей, т.е. в ней должна лежать:
1. Инфа по новости
2. id-шки к второстепенной инфе (к примеру для названия языка)
и для целостности не забудь foreign key :)
 

Slastik

Новичок
Автор оригинала: 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
        )

)
 

zerkms

TDD infected
Команда форума
Slastik
я же попросил идентифиактор языка - в условие объединения (ON)
 

Slastik

Новичок
zerkms я что то тебя не понимаю , каким образом я туда могу внести lang_id. Таблица articles не предпологает нахождения в ней языка. Там на каждую статью по одной записи.
 

berkut

Новичок
zerkmsа разве есть какая-то разница, где указывать lang_id - в on или where?
 

Slastik

Новичок
zerkms мой запрос выбирает статьи по определенной рубрике на указанном языке отсортированные по дате.. может ты немного не так меня понял..
 

zerkms

TDD infected
Команда форума
berkut
неужели оптимизатор такой умный, что всё сам сделает?

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

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

KEY `lang_id` (`lang_id`) можешь убрать, смысла в нём (в этом запросе конкретно) нету
 

Slastik

Новичок
Автор оригинала: 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?
 

zerkms

TDD infected
Команда форума
просто ты часть условия объединения (логика запроса, не оптимизация), поместил в WHERE, где оно быть в принципе не могло... из-за этого у тебя вся схема запроса расползлась...
 

Slastik

Новичок
почему lang_id быть впринципе там не могло? Поясни последнюю фразу плз. Мануал не рекомендует писать where условия в On.
Правда не понятно почему :)
 

zerkms

TDD infected
Команда форума
articles_test - инфа, не зависящая от языка
articles_loc_test - инфа, зависящая от языка

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

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

Slastik

Новичок
понял :) спасибо. Но where lang_id = 1 то ведь все равно остается.
 

zerkms

TDD infected
Команда форума
Slastik
НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ НЕТ
 
Сверху