#sql #performance
#sql #Производительность
Вопрос:
Немного сложный вопрос SQL здесь, объяснение ниже: лучше иметь 10 небольших таблиц «имен», идентичных во всех, кроме таблицы, к которой относятся их внешние ключи «ID», или иметь одну большую таблицу «имена», в которой столбец varchar указывает, для какой таблицы допустим столбец идентификатора?
(Я знаю, что есть похожие вопросы об «одном большом столе или нескольких маленьких», но ни один из них не соответствует тому, что меня интересует.)
Уточнение: У меня есть база данных SQL с более чем 10 основными таблицами и множеством подключаемых таблиц. В качестве примера представьте базу данных с таблицами « books
«, « authors
«, « publishers
«, « distributors
«, « artists
«, « characters
» и так далее.
Каждая из этих книг, издателей, художников и т.д. Может иметь более одного имени не только потому, что у них могут быть разные имена на разных языках, но и потому, что на самом деле у них может быть более одного имени на одном языке. Часто у них будет только один, но у них может быть несколько. У них может быть двадцать. Трудно сказать.
Каков самый простой способ обработки этого, с точки зрения таблиц SQL? Имея тонны столбцов «имя» в каждой таблице (например, по одному на язык), это не сработает, так как может быть более одного заголовка на язык (и большинство из этих столбцов все равно останутся пустыми). Некоторые из вариантов, о которых я думал:
- Одна отдельная таблица «имя» для каждой из этих таблиц, которая ссылается на столбец идентификатора родительской таблицы. Это работает, но выглядит действительно глупо (10 таблиц «_names»). И, поскольку все эти таблицы будут иметь один и тот же формат, одни и те же контрольные ограничения, это похоже на серьезный случай повторения. Если мне нужно изменить какое-то ограничение или спецификацию столбца, я должен сделать это в более чем 10 местах, а может быть, и больше, если появится еще одна основная таблица.
- Одна большая таблица «имена» со столбцами «имя таблицы» и «идентификатор», содержащая имена всех объектов. Но в итоге у меня получился бы довольно длинный список. И поскольку я не могу (или не знаю, как это сделать) разрешить столбцу varchar ссылаться на имя таблицы как на внешний ключ, я пропущу ограничение внешнего ключа.
- Объедините все таблицы «книги», «издатели» и т. Д. В большую таблицу под названием «Предметы» или «Вещи», чтобы ни одна книга не могла иметь тот же идентификатор, что и издатель, а затем создайте большую таблицу с «именами», как в примере (2). Таким образом, таблицы имен будут иметь функциональный внешний ключ, но просмотр базы данных будет сбивать с толку, так как вы больше не будете отделять «Книгу» от «Издателя». Все соединительные таблицы будут просто ссылаться на таблицу «Вещи», которая будет очень подвержена ошибочным отношениям.
- Имея одно длинное поле «имя» для каждой таблицы, и отформатируйте его каким-либо образом, например»
eng:Donald Duck, fre:Donald, nor:Anders And, swe:Kalle Anka
«. Таким образом, мне не придется объединяться с другими таблицами, чтобы найти имена, но каждый результат потребует анализа этой строки.
Я склоняюсь между решением (1) или (2). Наличие одного длинного списка имен кажется более аккуратным, чем наличие более чем 10 одинаковых таблиц «имена», и это облегчит «общий поиск». Но я беспокоюсь, что большая таблица замедлит процесс поиска, особенно при наличии нескольких соединений, которые все выполняют поиск по этой таблице имен. Представьте, что в каждой из этих сущностей 1000, а среднее значение составляет 2 имени в строке. Вместо
SELECT NAME FROM BOOK_TITLES WHERE ID=? AND LANG=?
из списка в 2000 человек у меня будет
SELECT NAME FROM NAMES WHERE TYPE='BOOK' AND ID=? AND LANG=?
из списка в 20 000 человек. И я даже не могу позволить «Type ID lang» быть первичным ключом, поскольку для одной и той же книги может быть несколько названий на одном и том же языке, поэтому я полагаю, что поиск будет довольно неоптимальным в случае сложного запроса, который ищет книгу и должен дать результат с именами издателей, художников, персонажей и т. Д., И все они будут искать в этой таблице 20 000 строк (и в конце концов она может быть намного длиннее 20 000) Без каких-либо первичных ключей.
У кого-нибудь есть какие-либо идеи о том, что было бы лучшим решением?
Комментарии:
1. В чем заключается цель
name
? Краткое описание юридического лица. Глядя наname
него , человек должен понимать, какая именно запись им указана. Какова цель иметь разные имена для одной и той же записи и на одном и том же языке?2. Никакой другой цели, кроме как просто реальность. Это похоже на то, что «Властелин колец» также известен как «ЛОТР» или даже «Властелин колец». В базе данных, над которой я работаю, это не часто встречается, но такое случается, поэтому база данных должна соответствовать требованиям. Если для каждого языка и элемента может быть только одно имя, то это может составить первичный ключ и устранит (некоторые) проблемы с производительностью, которые у меня есть.
3. таким образом, вы можете ввести грязные данные. Представьте, что люди по ошибке войдут в «Властелин колец», «Властелин колец». Названия книг не имеют синонимов, во всех базах данных у них одно название. В комментарии в редких случаях вы можете сказать, что это известно как «что-то другое». Вы должны заставить себя не вводить данные по ошибке. Представьте, какое имя вы бы показали клиенту в графическом интерфейсе или в отчете? Будет выбрано одно имя. Все остальные имена — это просто дополнительная информация, которую вы могли бы сохранить в виде комментария, возможно, в отдельной таблице, если вы встречаете ее очень редко.
4. Для книг да, но книги-это всего лишь пример, а не база данных, с которой я работаю. Тот, с которым я работаю, с несколькими именами-это нечто необычное, но не редкое и, безусловно, необходимое для отслеживания. Я бы не получил многого от наличия «лишних» имен в отдельной таблице, так как мне в любом случае нужно было бы просмотреть эту «лишнюю» таблицу, чтобы получить все необходимые имена, даже если бы у меня было имя «по умолчанию» в основной таблице. Конечно, введенная информация должна быть подтверждена. Грязные данные всегда являются проблемой, независимо от того, есть ли у вас одно имя или несколько.
Ответ №1:
Отделите идентификатор от имени.
Используйте автоматически увеличиваемый идентификатор (или создайте свой собственный код для удобства использования) для каждой книги/издателя/и т.д…
Вместо того, чтобы искать имя, найдите код книги и только затем получите все связанные имена.
В идеале вы бы получили такой запрос
SELECT B.*, N.* -- ideally, you'd pivot here, this is an example FROM BOOK B JOIN NAMES ON B.code = N.bookCode WHERE B.code = 1
Имейте одну таблицу имен для каждого типа вещей (книга, издатель и т. Д.). Это не повторение самого себя. Это хороший дизайн базы данных. Вам не нужно менять таблицу имен, если только что-то не пошло не так во время создания.
Итак, вариант 1.
Вы все еще можете создать представление, объединяющее значения имен, если это необходимо для целей поиска.
Вы не можете создать первичный ключ для неуникальных значений, но вы все равно можете создать индекс, если считаете, что эта конкретная комбинация полей будет часто использоваться.
Комментарии:
1. Спасибо. Я представлял себе, что это был бы лучший вариант, но мне показалось странным, что так много столов были почти идентичны. (Кроме того, я полагаю, вы имеете в виду
FROM BOOK B JOIN NAMES N ON B.code = N.bookCode
)