Есть ли причина беспокоиться о порядке столбцов в таблице?

84

Я знаю, что вы можете ИЗМЕНИТЬ порядок столбцов в MySQL с помощью FIRST и AFTER, но зачем вам беспокоиться? Поскольку в хороших запросах при вставке данных столбцы явно называются, есть ли причина заботиться о том, в каком порядке находятся столбцы в таблице?

Линн
источник

Ответы:

94

Порядок столбцов оказал большое влияние на производительность некоторых настраиваемых мной баз данных, включая Sql Server, Oracle и MySQL. В этом посте есть хорошие практические правила :

  • Сначала столбцы первичного ключа
  • Следующие столбцы внешнего ключа.
  • Столбцы, которые часто ищут, далее
  • Часто обновляемые столбцы позже
  • Обнуляемые столбцы идут последними.
  • Наименее используемые столбцы, допускающие значение NULL, после более часто используемых столбцов, допускающих значение NULL

Примером разницы в производительности является поиск по индексу. Механизм базы данных находит строку на основе некоторых условий в индексе и возвращает адрес строки. Теперь предположим, что вы ищете SomeValue, и он находится в этой таблице:

 SomeId int,
 SomeString varchar(100),
 SomeValue int

Движок должен угадать, где начинается SomeValue, потому что SomeString имеет неизвестную длину. Однако, если вы измените порядок на:

 SomeId int,
 SomeValue int,
 SomeString varchar(100)

Теперь движок знает, что SomeValue можно найти через 4 байта после начала строки. Таким образом, порядок столбцов может иметь значительное влияние на производительность.

РЕДАКТИРОВАТЬ: Sql Server 2005 хранит поля фиксированной длины в начале строки. И каждая строка имеет ссылку на начало varchar. Это полностью сводит на нет указанный выше эффект. Таким образом, для недавних баз данных порядок столбцов больше не влияет.

Андомар
источник
4
@TopBanana: не с varchars, это то, что отличает их от обычных столбцов char.
Аллен Лалонде
1
Я не думаю, что порядок столбцов В ТАБЛИЦЕ имеет какое-либо значение - это определенно влияет на ИНДЕКСЫ, которые вы можете создать, правда.
marc_s
4
@TopBanana: не уверен, знаете ли вы Oracle или нет, но он не резервирует 100 байт для VARCHAR2 (100)
Quassnoi
1
@Quassnoi: наибольшее влияние оказал Sql Server, таблица с множеством столбцов varchar (), допускающих значение NULL.
Andomar
7
URL-адрес в этом ответе больше не работает, есть ли у кого-нибудь альтернативный?
scunliffe
41

Обновить:

В MySQL, может быть причина для этого.

Поскольку переменные типы данных (например VARCHAR) хранятся с переменной длиной в InnoDB, движок базы данных должен пройти все предыдущие столбцы в каждой строке, чтобы узнать смещение данного столбца.

Воздействие может быть как 17% для 20столбцов.

См. Эту запись в моем блоге для более подробной информации:

В Oracleконечные NULLстолбцы не занимают места, поэтому вы всегда должны помещать их в конец таблицы.

Также в Oracleи в SQL Serverслучае большого рядаROW CHAINING может произойти.

ROW CHANING разбивает строку, которая не помещается в один блок, и распределяет ее на несколько блоков, связанных связным списком.

Чтение завершающих столбцов, которые не помещаются в первый блок, потребует обхода связанного списка, что приведет к дополнительной I/Oоперации.

См. Эту страницу для иллюстрации ROW CHAININGв Oracle:

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

Важная заметка:

Если вам понравился этот ответ и вы хотите проголосовать за него, проголосуйте также за @Andomar ответ .

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

Quassnoi
источник
1
Итак, вы говорите, что это будет медленно: выберите tinyTable.id, tblBIG.firstColumn, tblBIG.lastColumn из внутреннего соединения tinyTable tblBIG на tinyTable.id = tblBIG.fkID Если размер записей tblBIG превышает 8 КБ (в этом случае произойдет цепочка строк ), и соединение будет синхронным ... Но это будет быстро: выберите tinyTable.id, tblBIG.firstColumn из внутреннего соединения tinyTable tblBIG на tinyTable.id = tblBIG.fkID Так как я бы не стал использовать столбец в других блоках, следовательно, нет необходимо просмотреть связанный список. Я правильно понял?
jfrobishow
1
Я получаю только 6%, и это для столбца col1 по сравнению с любым другим столбцом.
Рик Джеймс
6

Во время обучения Oracle на предыдущей работе наш администратор баз данных предположил, что размещение всех столбцов, не допускающих значения NULL, перед столбцами, допускающими значение NULL, было выгодным ... хотя, ЧБХ, я не помню деталей, почему. Или, может быть, в конце должны быть отправлены только те, которые, вероятно, будут обновлены? (Возможно, откладывает необходимость перемещать строку, если она расширяется)

В общем, никакой разницы не должно быть. Как вы говорите, запросы всегда должны указывать сами столбцы, а не полагаться на порядок из "select *". Я не знаю ни одной БД, которая позволяет их изменять ... ну, я не знал, что MySQL разрешает это, пока вы не упомянули об этом.

аракнид
источник
4
Он был прав, Oracle не записывает завершающие столбцы NULL на диск, экономя несколько байтов. См. Dba-oracle.com/oracle_tips_ault_nulls_values.htm
Андомар,
абсолютно, это может иметь большое значение в размере на диске
Alex
Вы это имели в виду? Это связано с отсутствием индексации нуля в индексах, а не с порядком столбцов.
araqnid
Неверная ссылка, и не удается найти оригинал. Хотя вы можете найти это в Google, например tlingua.com/new/articles/Chapter2.html
Andomar
5

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

Крейг Уокер
источник
3
Разработчики приложений, которые делают свой код зависимым от порядка столбцов в таблице, ДОЛЖНЫ, чтобы их приложения были сломаны. Но пользователи приложения не заслуживают отключения.
spencer7593
4

Читаемость вывода, когда вам нужно набрать:

select * from <table>

в вашем программном обеспечении для управления базами данных?

Это очень надуманная причина, но сейчас я не могу думать ни о чем другом.

ChrisF
источник
4

Нет, порядок столбцов в таблице базы данных SQL совершенно не имеет значения - за исключением целей отображения / печати. Нет смысла переупорядочивать столбцы - большинство систем даже не предоставляют способ сделать это (кроме удаления старой таблицы и воссоздания ее с новым порядком столбцов).

Марк

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

Отношение определяется как набор из n кортежей. И в математике, и в модели реляционной базы данных набор представляет собой неупорядоченный набор элементов, хотя некоторые СУБД устанавливают порядок для своих данных. В математике кортеж имеет порядок и допускает дублирование. Первоначально EF Codd определял кортежи, используя это математическое определение. Позже Э. Ф. Кодд пришел к выводу, что использование имен атрибутов вместо упорядочивания было бы намного удобнее (в целом) в компьютерном языке, основанном на отношениях. Это понимание все еще используется сегодня.

marc_s
источник
1
Я своими глазами видел, как разница в столбцах оказывает большое влияние, поэтому не могу поверить, что это правильный ответ. Хотя голосование ставит это на первое место. Грм.
Andomar
В какой среде SQL это будет?
marc_s
1
Наибольшее влияние, которое я видел, было на Sql Server 2000, где перемещение внешнего ключа вперед ускорило некоторые запросы в 2–3 раза. В этих запросах выполнялось сканирование больших таблиц (более 1 млн строк) с условием для внешнего ключа.
Andomar
5
СУБД не зависит от порядка таблиц, если вы не заботитесь о производительности . Различные реализации будут иметь разные потери производительности для порядка столбцов. Он может быть огромным или маленьким, в зависимости от реализации. Кортежи теоретические, СУБД практические.
Эстебан Кюбер
3
-1. Все реляционные базы данных, которые я использовал, ДОЛЖНЫ иметь порядок столбцов на каком-то уровне. Если вы выберете * из таблицы, вы не вернете столбцы в случайном порядке. Теперь разные дискуссии о дисках и дисплеях. И цитирование теории математики в качестве подтверждения предположения о практической реализации баз данных - просто нонсенс.
DougW,
2

Единственная причина, о которой я могу думать, - это отладка и пожаротушение. У нас есть таблица, столбец «name» которой занимает 10-е место в списке. Больно, когда вы быстро выбираете * из таблицы, где идентификатор находится в (1,2,3), а затем вам нужно прокручивать, чтобы посмотреть на имена.

Но это все.

Крис Симпсон
источник
1

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

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

Если вы собираетесь часто использовать UNION, сопоставление столбцов будет проще, если у вас есть соглашение об их порядке.

Аллен Лалонд
источник
Похоже, ваша база данных нуждается в нормализации! :)
Джеймс Л.
Привет! Верни, я не сказал свою базу данных. :)
Аллен Лалонде
Существуют законные причины для использования UNION;) См. Postgresql.org/docs/current/static/ddl-partitioning.html и stackoverflow.com/questions/863867/…
Эстебан Кюбер
Можете ли вы ОБЪЕДИНЯТЬ порядок столбцов в 2 таблицах в разном порядке?
Моника Хедднек 01
Да, вам просто нужно явно указать столбцы при запросе таблиц. Для таблиц A [a, b] B [b, a] это означает (SELECT aa, ab FROM A) UNION (SELECT ba, bb FROM B) вместо (SELECT * FROM A) UNION (SELECT * FROM B).
Allain Lalonde
1

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

Конечно, любые последствия для производительности сильно зависят не только от производителя, которого вы используете, но и, возможно, от версии. Несколько месяцев назад я заметил, что наши Postgres не могут использовать индекс для сравнения «нравится». То есть, если вы написали «somecolumn like 'M%'», было недостаточно умен, чтобы перейти к M и выйти, когда он нашел первый N. Я планировал изменить кучу запросов, чтобы использовать «между». Потом у нас появилась новая версия Postgres, и она грамотно справилась с подобными вещами. Рад, что мне так и не удалось изменить запросы. Очевидно, здесь это не имеет прямого отношения, но я хочу сказать, что все, что вы делаете из соображений эффективности, может устареть в следующей версии.

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

Джей
источник
1

Помимо очевидной настройки производительности, я просто столкнулся с угловым случаем, когда изменение порядка столбцов приводило к сбою (ранее работавшего) сценария sql.

Из документации «столбцы TIMESTAMP и DATETIME не имеют автоматических свойств, если они не указаны явно, за этим исключением: по умолчанию первый столбец TIMESTAMP имеет как DEFAULT CURRENT_TIMESTAMP, так и ON UPDATE CURRENT_TIMESTAMP, если ни один из них не указан явно» https: //dev.mysql .com / doc / refman / 5.6 / ru / timestamp-initialization.html

Итак, команда ALTER TABLE table_name MODIFY field_name timestamp(6) NOT NULL; будет работать, если это поле является первой меткой времени (или даты и времени) в таблице, но не иначе.

Очевидно, вы можете исправить эту команду alter, включив в нее значение по умолчанию, но тот факт, что работавший запрос перестал работать из-за переупорядочения столбцов, у меня разболелась голова.

бездельник525600
источник
0

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

Совиут
источник
0

В общем, что происходит в SQL Server, когда вы меняете порядок столбцов с помощью Management Studio, так это то, что он создает временную таблицу с новой структурой, перемещает данные в эту структуру из старой таблицы, удаляет старую таблицу и переименовывает новую. Как вы могли догадаться, это очень плохой выбор с точки зрения производительности, если у вас большая таблица. Я не знаю, делает ли мой SQL то же самое, но это одна из причин, по которой многие из нас избегают переупорядочивания столбцов. Поскольку select * никогда не следует использовать в производственной системе, добавление столбцов в конце не является проблемой для хорошо спроектированной системы. Порядок столбцов в таблице не должен изменяться.

HLGEM
источник
0

В 2002 году Билл Торстейнсон разместил на форумах Hewlett Packard свои предложения по оптимизации запросов MySQL путем изменения порядка столбцов. С тех пор его пост буквально копировали и расклеивали в Интернете не менее сотни раз, часто без цитирования. Процитировать его точно ...

Общие практические правила:

  • Сначала столбцы первичного ключа.
  • Следующие столбцы внешнего ключа.
  • Следующие столбцы, которые часто ищут.
  • Часто обновляемые столбцы позже.
  • Обнуляемые столбцы идут последними.
  • Наименее используемые столбцы, допускающие значение NULL, после более часто используемых столбцов, допускающих значение NULL.
  • BLOB-объекты в собственной таблице с несколькими другими столбцами.

Источник: форумы HP.

Но этот пост был сделан еще в 2002 году! Этот совет был для MySQL версии 3.23, более чем за шесть лет до выпуска MySQL 5.1. И никаких ссылок или цитат. Итак, был ли Билл прав? И как именно на этом уровне работает механизм хранения?

  1. Да, Билл был прав.
  2. Все сводится к объединению строк и блоков памяти.

Процитируем Мартина Зана, сертифицированного специалиста Oracle , из статьи о секретах цепочки строк и миграции Oracle ...

Связанные строки по-разному влияют на нас. Здесь это зависит от того, какие данные нам нужны. Если бы у нас была строка с двумя столбцами, распределенная по двум блокам, запрос:

SELECT column1 FROM table

где column1 находится в блоке 1, не приведет к «продолжению строки выборки таблицы». На самом деле ему не нужно было бы получать column2, он не будет следовать за связанной строкой полностью. С другой стороны, если мы попросим:

SELECT column2 FROM table

а column2 находится в блоке 2 из-за цепочки строк, тогда вы фактически увидите «непрерывную строку выборки таблицы»

Остальную часть статьи неплохо прочитать! Но я цитирую здесь только ту часть, которая имеет прямое отношение к нашему вопросу.

Спустя более 18 лет я должен сказать это: спасибо, Билл!

Отображение строки MySQL в блок данных

HoldOffHunger
источник