Чи є підстави турбуватися про порядок стовпців у таблиці?


84

Я знаю, що ви можете ЗМІНИТИ порядок стовпців у MySQL за допомогою FIRST та AFTER, але чому ви хочете турбуватись? Оскільки хороші запити явно називають стовпці під час вставки даних, чи дійсно є причина дбати про те, в якому порядку ваші стовпці в таблиці?

Відповіді:


94

Порядок стовпців мав великий вплив на продуктивність деяких баз даних, які я вже налаштував, що охоплюють Sql Server, Oracle та MySQL. Цей допис має хороші емпіричні правила :

  • Спочатку стовпці первинного ключа
  • Далі стовпці зовнішнього ключа.
  • Далі часто шукані стовпці
  • Пізніше часто оновлювані стовпці
  • Нульові стовпці останні.
  • Найменш використовувані стовпчики, що дозволяють обнулятись, після часто використовуваних стовпців, що дозволяють обнуляти

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

 SomeId int,
 SomeString varchar(100),
 SomeValue int

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

 SomeId int,
 SomeValue int,
 SomeString varchar(100)

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

EDIT: Sql Server 2005 зберігає поля фіксованої довжини на початку рядка. І кожен рядок має посилання на початок varchar. Це повністю заперечує ефект, який я перерахував вище. Тож для останніх баз даних порядок стовпців більше не впливає.


4
@TopBanana: не з varchars, це те, що відрізняє їх від звичайних стовпців char.
Аллаін Лалонд

1
Я не думаю, що порядок стовпців У ТАБЛИЦІ має якесь значення - це, безумовно, має значення в ІНДЕКСАХ, які ви можете створити, правда.
marc_s

4
@TopBanana: не впевнений, знаєте ви Oracle чи ні, але він не резервує 100 байт для VARCHAR2 (100)
Квасной

1
@Quassnoi: найбільший вплив справив на Sql Server, на таблиці з великою кількістю стовпців varchar ().
Андомар,

7
URL-адреса в цій відповіді більше не працює, чи є у когось альтернатива?
scunliffe

41

Оновлення:

У Росії MySQLможе бути причина для цього.

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

Вплив може бути до 17% для 20стовпців.

Детальніше див. Цей запис у моєму блозі:

У Oracle, кінцеві NULLстовпці не займають місця, тому ви завжди повинні розміщувати їх у кінці таблиці.

Також у Oracleі в SQL Server, у випадку великого ряду, ROW CHAININGможе траплятися a .

ROW CHANING розбиває рядок, який не вміщується в один блок, і охоплює його по декількох блоках, пов’язаних пов’язаним списком.

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

Див. Цю сторінку для ілюстрації ROW CHAININGв Oracle:

Ось чому слід розміщувати часто використовувані стовпці на початку таблиці, а нечасто використовувані стовпці або стовпці, які, як правило, є NULL, до кінця таблиці.

Важлива примітка:

Якщо вам подобається ця відповідь і ви хочете проголосувати за неї, просимо також проголосувати за @Andomarвідповідь .

Він відповів те саме, але, схоже, його без голосу віддали.


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 на попередній роботі наш DBA запропонував вигідне розміщення всіх ненульованих стовпців перед нульовими ... хоча TBH я не пам’ятаю деталей, чому. А може, саме ті, які, ймовірно, оновлюватимуться, повинні піти в кінці? (Можливо, відкладає необхідність переміщення рядка, якщо він розширюється)

Загалом, це не повинно мати жодної різниці. Як ви говорите, запити завжди повинні вказувати самі стовпці, а не покладатися на впорядкування від "select *". Я не знаю жодної БД, яка дозволяє їх змінювати ... ну, я не знав, що MySQL дозволяв це, поки ви про це не згадали.


4
Він мав рацію, Oracle не записує кінцеві стовпці NULL на диск, зберігаючи деякі байти. Дивіться dba-oracle.com/oracle_tips_ault_nulls_values.htm
Андомар

абсолютно, це може сильно змінити розмір диска
Алекс,

Це посилання, яке ви мали на увазі? Це пов’язано з неіндексуванням нульового значення в індексах, а не порядком стовпців.
araqnid

Неправильне посилання, і не вдається знайти оригінал. Хоча ви можете погуглити
Andomar

5

Деякі погано написані програми можуть залежати від порядку / індексу стовпців замість імені стовпця. Вони не повинні бути, але це трапляється. Зміна порядку стовпців призведе до порушення таких програм.


3
Розробники додатків, які роблять свій код залежним від порядку стовпців у таблиці ЗАСЛУЖУВАТИ, щоб їх програми розбивалися. Але користувачі програми не заслуговують відключення.
spencer7593

4

Легкість читання результату, коли потрібно ввести:

select * from <table>

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

Це дуже хибна причина, але на даний момент я не можу придумати нічого іншого.


4

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

Марк

РЕДАКТУВАТИ: із запису Вікіпедії про реляційну базу даних, ось відповідна частина, яка для мене чітко показує, що порядок стовпців ніколи не повинен відбуватися викликати занепокоєння:

Відношення визначається як набір n-кортежів. І в математиці, і в моделі реляційної бази даних набір - це невпорядкована колекція елементів, хоча деякі СУБД накладають порядок на свої дані. У математиці кортеж має порядок і дозволяє дублювати. EF Codd спочатку визначав кортежі, використовуючи це математичне визначення. Пізніше це було одне з чудових розумінь Е.Ф. Кодда про те, що використання імен атрибутів замість упорядкування було б набагато зручнішим (загалом) у комп'ютерній мові, заснованій на відносинах. Це розуміння використовується і сьогодні.


1
Я бачив, як різниця у стовпцях має великий вплив на власні очі, тому не можу повірити, що це правильна відповідь. Хоча голосування ставить це на перше місце. Хв.
Андомар,

В якому середовищі SQL це буде?
marc_s

1
Найбільший вплив, який я бачив, був на Sql Server 2000, де переміщення зовнішнього ключа вперед прискорило деякі запити в 2-3 рази. Ці запити мали сканування великих таблиць (1 млн + рядків) із умовою зовнішнього ключа.
Андомар,

5
СУБД не залежать від замовлення таблиць, якщо ви не дбаєте про продуктивність . Різні реалізації матимуть різні покарання продуктивності для порядку стовпців. Це може бути величезним, а може бути і крихітним, це залежить від реалізації. Кортежі теоретичні, СУБД практичні.
Естебан Кюбер

3
-1. Усі реляційні бази даних, якими я користувався, мають порядок стовпців на певному рівні. Якщо ви вибрали * з таблиці, ви не прагнете повернути стовпці у довільному порядку. Зараз на диску проти дисплея - це інша дискусія. А посилання на теорію математики для підтвердження припущення про практичне впровадження баз даних - це просто нісенітниця.
DougW

2

Єдина причина, про яку я можу думати, - це налагодження та пожежогасіння. У нас є таблиця, стовпець "імені" якої знаходиться приблизно на 10 місці у списку. Це болісно, ​​коли ви швидко робите * з таблиці, де id у (1,2,3), а потім вам потрібно прокрутити, щоб переглянути імена.

Але це все.


1

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


Зазвичай ми починаємо з останнього стовпця, який «створюється» (позначка часу, коли вставляється рядок). Зі старішими таблицями, звичайно, після цього можна додати кілька стовпців ... І у нас є випадкова таблиця, де складений первинний ключ був змінений на сурогатний ключ, тому первинний ключ має кілька стовпців.
аракнід

1

Якщо ви збираєтеся використовувати UNION багато, це полегшує відповідність стовпців, якщо у вас є домовленість про їх впорядкування.


Здається, ваша база даних потребує нормалізації! :)
Джеймс Л,

Гей! Візьміть назад, я не сказав свою базу даних. :)
Аллаін Лалонд

Існують допустимі причини використання UNION;) Див. Postgresql.org/docs/current/static/ddl-partitioning.html і stackoverflow.com/questions/863867 / ...
Естебан KUBER

Ви можете UNION, коли порядок стовпців у 2 таблицях знаходиться в іншому порядку?
Моніка Хеднек

Так, вам просто потрібно чітко вказати стовпці під час запитів таблиць. У таблицях A [a, b] B [b, a] це означає (SELECT aa, ab FROM A) UNION (SELECT ba, bb FROM B), який містить (SELECT * FROM A) UNION (SELECT * FROM B).
Аллаін Лалонд

1

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

Звичайно, будь-які наслідки для продуктивності сильно залежать не тільки від виробника, який ви використовуєте, але й потенційно від версії. Кілька місяців тому я помітив, що наш Postgres не може використовувати індекс для порівняння "як". Тобто, якщо ви написали "якийсь стовпець на зразок" М% "", він був недостатньо розумним, щоб перейти до М і вийти, коли знайшов першу Н. Я планував змінити купу запитів, щоб використовувати "між". Тоді ми отримали нову версію Postgres, і вона розумно обробляла подібні. Радий, що я ніколи не міг змінити запити. Очевидно, тут це не має прямого відношення, але я хочу сказати, що все, що ви робите з міркувань ефективності, може застаріти з наступною версією.

Порядок стовпців майже завжди дуже актуальний для мене, оскільки я регулярно пишу загальний код, який читає схему бази даних для створення екранів. Мої екрани "редагувати запис" майже завжди будуються шляхом читання схеми, щоб отримати список полів, а потім відображаючи їх по порядку. Якби я змінив порядок стовпців, моя програма все одно працювала б, але відображення може бути дивним для користувача. Мовляв, ви очікуєте побачити ім’я / адресу / місто / штат / поштовий індекс, а не місто / адресу / поштовий індекс / ім’я / штат. Звичайно, я міг би встановити порядок відображення стовпців у коді або в керуючому файлі, або щось інше, але тоді кожного разу, коли ми додавали або видаляли стовпець, нам потрібно було пам’ятати, щоб перейти до оновлення керуючого файлу. Я люблю щось говорити. Крім того, коли екран редагування будується виключно зі схеми, додавання нової таблиці може означати написання нульових рядків коду для створення екрана редагування для неї, що дуже класно. (Ну, добре, на практиці, як правило, мені доводиться додавати запис до меню, щоб викликати загальну програму редагування, і я загалом відмовився від загального "вибрати запис для оновлення", оскільки є занадто багато винятків, щоб зробити це практичним .)


1

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

З документації "Стовпці TIMESTAMP і DATETIME не мають автоматичних властивостей, якщо вони не вказані явно, за винятком цього: За замовчуванням перший стовпець TIMESTAMP має як DEFAULT CURRENT_TIMESTAMP, так і ON UPDATE CURRENT_TIMESTAMP, якщо жоден з них не вказаний явно" https: //dev.mysql .com / doc / refman / 5.6 / en / timestamp-initialization.html

Отже, команда ALTER TABLE table_name MODIFY field_name timestamp(6) NOT NULL; буде працювати, якщо це поле є першою позначкою часу (або датою і часом) у таблиці, але не інакше.

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


0

Єдиний раз, коли вам доведеться турбуватися про порядок стовпців, це якщо ваше програмне забезпечення конкретно покладається на це замовлення. Зазвичай це пов'язано з тим, що розробник полінувався і зробив a, select *а потім посилався на стовпці за індексом, а не за іменем у своєму результаті.


0

Загалом, те, що відбувається в SQL Server при зміні порядку стовпців через Management Studio, полягає в тому, що він створює тимчасову таблицю з новою структурою, переміщує дані до цієї структури зі старої таблиці, скидає стару таблицю та перейменовує нову. Як ви могли собі уявити, це дуже поганий вибір для продуктивності, якщо у вас великий стіл. Я не знаю, чи робить My SQL те саме, але це одна з причин, чому багато хто з нас уникає переупорядкування стовпців. Оскільки select * ніколи не слід використовувати у виробничій системі, додавання стовпців у кінці не є проблемою для добре розробленої системи. Порядок стовпців у таблиці загалом не повинен переплутатися.


0

У 2002 році Білл Торстайнсон розмістив на форумах Hewlett Packard свої пропозиції щодо оптимізації запитів MySQL шляхом перестановки стовпців. З тих пір його допис буквально копіювали та вставляли щонайменше сто разів в Інтернет, часто без цитування. Якщо точно цитувати його ...

Загальні правила:

  • Спочатку стовпці первинного ключа.
  • Далі стовпці зовнішнього ключа.
  • Наступні стовпці, які часто шукають.
  • Пізніше часто оновлювані стовпці.
  • Нульові стовпці останні.
  • Найменш використовувані дозвільні стовпці після часто використовуваних дозвільних стовпців.
  • Краплі у власній таблиці з кількома іншими стовпцями.

Джерело: HP Forums.

Але ця посада була зроблена ще в 2002 році! Ця порада стосувалася MySQL версії 3.23, більш ніж за шість років до виходу MySQL 5.1. І тут немає посилань чи цитат. Отже, Білл мав рацію? І як саме працює механізм зберігання на цьому рівні?

  1. Так, Білл мав рацію.
  2. Все зводиться до питання ланцюгових рядків та блоків пам'яті.

Процитувавши Мартіна Зана, професіонала , сертифікованого Oracle , у статті про “Секрети ланцюжкового ланцюжка та міграції Oracle” ...

Прикуті ряди впливають на нас по-різному. Тут це залежить від даних, які нам потрібні. Якби у нас був рядок із двома стовпцями, який був розподілений на два блоки, запит:

SELECT column1 FROM table

де стовпець1 стоїть у блоці 1, не спричинить жодного «рядка продовження отримання таблиці». Насправді йому не потрібно було б отримувати column2, він би не слідував за ланцюжковим рядком до кінця. З іншого боку, якщо ми просимо:

SELECT column2 FROM table

і стовпець2 знаходиться в Блоці 2 через ланцюжок рядків, тоді ви насправді побачите «продовження рядка отримання таблиці»

Решта статті - досить гарне читання! Але я цитую лише ту частину, яка безпосередньо стосується нашого розглядуваного питання.

Більше 18 років потому я повинен сказати це: дякую, Білл!

Прив'язка рядка MySQL до блоку даних

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.