SQL SELECT швидкість int vs varchar


110

Я в процесі створення таблиці, і це змусило мене замислитися.

Якщо я зберігаю, скажімо, автомобілі, які мають марку (fx BMW, Audi ect.), Чи це змінить швидкість запиту, якщо я зберігаю марку як int або varchar.

Так і є

SELECT * FROM table WHERE make = 5 AND ...;

Швидше / повільніше, ніж

SELECT * FROM table WHERE make = 'audi' AND ...;

чи швидкість буде більш-менш однаковою?

Відповіді:


99

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

Це справедливо як для неіндексованого, так і для індексованого доступу. Найшвидший шлях - індексований стовпець int.


Як я бачу, ви позначели тегом postgreql, можливо, вас зацікавить використання простору різних типів дати:


13
Ви посилаєтесь на сторінку 7.4. У сучасних версіях вони займають 1 байт + довжину, якщо у вас <126 байт. Також зауважте, що причина рядків набагато повільніше полягає в тому, що порівняння з урахуванням порівняння дуже дороге - не те, що рядок займає більше місця. Але кінцевий результат, звичайно, такий же.
Магнус Хагандр

@Magnus - спасибі за голову. Не соромтесь редагувати мою відповідь, оскільки я бачу, що у вас є достатня кількість балів повторень.
Роберт Мунтяну

"не те, що рядок займає більше місця" ... рядки символів вище мінімальних розмірів займають чортівку набагато більше місця, ніж навіть високоточні числа, тому що число (однина) має фіксовану одиницю, рядки - це завжди сукупні типи . 8 байт для 64-бітного числа 4 байти на символ у рядку, включаючи або байт довжини, або структуру; або інший символ термінатора для неймовірно наївних реалізацій ...
MrMesees

@RobertMunteanu Ей Роберт, вибачте, я знаю, що це стара публікація, але чи можу я люб’язно перевірити ... на наступне: для запиту цілих чисел я повинен зв’язати кожен стовпчик рядків до іншої таблиці (відносини). однак це означає, що для кожного запиту потрібно більше операцій приєднання. Як я можу визначити, чи вартий цей компроміс? Дякую!
AiRiFiEd

2
"Внутрішнє порівняння швидше, ніж порівняння з вархаром, для простого факту, що інти займають набагато менше місця, ніж вархари" - це НЕ справедливо взагалі . Залежно від СУБД, яку ви використовуєте, і точних типів даних та рядків, які ви хочете вставити, може виявитися, що ваші (скажімо, 8-байтні вкладиші довші, ніж варшарі ascii, що містять деякі текстові ідентифікатори довжиною середньої довжини 3-4 символи. Отже, ця відповідь - неточна і не має будь-якого конкретного контексту або експериментальних результатів - насправді не відповідає на питання. Всім відомо, що варшарам дозволено зайняти набагато більше місця, ніж інти, але вони НЕ повинні.
Марцін Войнарський

36

Деякі приблизні орієнтири:

4 мільйони записів у Postgres 9.x

Table A = base table with some columns
Table B = Table A + extra column id of type bigint with random numbers
Table C = Table A + extra column id of type text with random 16-char ASCII strings

Результати на 8 Гб оперативної пам’яті, i7, SSD ноутбука:

Size on disk:                A=261MB        B=292MB        C=322MB
Non-indexed by id: select count(*), select by id: 450ms same on all tables
Insert* one row per TX:       B=9ms/record        C=9ms/record
Bulk insert* in single TX:    B=140usec/record    C=180usec/record
Indexed by id, select by id:  B=about 200us       C=about 200us

* inserts to the table already containing 4M records

так це виглядає як для цієї установки, якщо ваші індекси вміщуються в оперативній пам'яті, текст bigint vs 16-char не має різниці в швидкості.


6
Дуже цікаво. Чому різниця незначна?
Chibueze Opata

18

Це буде трохи швидше, використовуючи int замість varchar. Більш важливим для швидкості є наявність індексу на полі, який запит може використовувати для пошуку записів.

Є ще одна причина використання int, а це нормалізація бази даних. Замість того, щоб текст "Мерседес-Бенц" зберігався тисячі разів у таблиці, ви повинні зберігати його ідентифікатор і один раз зберігати назву марки в окремій таблиці.


Чи можете ви пояснити більше? Ви маєте на увазі замість того, Mercedes-Benzщоб зберігати тисячі разів id 1. Наприклад таблиця car_brands, стовпці Brandsта Id. Ряд Mercedes-Benzі 1. І в стовпці Brandsта значенні основної таблиці 1. А коли SELECT, то спочатку вставай Idз-за столу, car_brandsа потім SELECT Something FROM main_table WHERE Brands = (SELECT Id FROM car_brands WHERE Brands = Mercedes-Benz). Або якийсь інший підхід?
Андріс

3
@ user2118559: Так, ви б так зберігали його. Для того, щоб отримати дані, як правило , використовують об'єднання , а не підзапиту: select something from main_table c inner join car_brands b on b.Id = c.Brands where b.Brands = 'Mercedes-Benz'.
Гуффа

Чому потік? Якщо ви не поясните, що ви вважаєте неправильним, це не може покращити відповідь.
Гуффа

8

Зводячись до фактичної продуктивності порівняння рядків проти неплавких, у цьому випадку будь-який розмір без підпису та підпису не має значення. Розмір насправді є справжньою різницею в продуктивності. Будь то 1 байт + (до 126 байт) порівняно з 1,2,4 або 8 байт порівняння ... очевидно, що без плавання менше, ніж рядки і плавки, і, таким чином, більш дружній з процесором в збірці.

Порівняння рядків на всіх мовах відбувається повільніше, ніж те, що може бути порівняно в 1 інструкції процесором. Навіть порівнюючи 8 байт (64 біт) на 32-бітовому процесорі все-таки швидше, ніж VARCHAR (2) або більше. * Знову ж таки, подивіться на виготовлену збірку (навіть вручну) потрібно більше вказівок для порівняння знаків за діаграмою, ніж від 1 до 8 байт цифрового процесора.

Тепер, наскільки швидше? залежить також від обсягу даних. Якщо ви просто порівнюєте 5 з "ауді" - і це все, що має ваш БД, різниця в результаті настільки мінімальна, що ви його ніколи не побачите. Залежно від процесора, імплементації (клієнт / сервер, веб / скрипт тощо) ви, мабуть, не побачите його, доки не потрапите на кілька сотень порівнянь на сервері БД (можливо, навіть пару тисяч порівнянь, перш ніж це буде помітно).

  • Анулювати невірну суперечку про порівняння хеш-книг. Більшість алгоритмів хешування самі по собі повільні, тому ви не маєте користі від таких речей, як CRC64 і менші. Протягом 12 років я розробляв алгоритми пошуку для пошукових систем для кількох округів та 7 років для бюро кредитів. Все, що ви можете зберегти в цифрі, швидше ... наприклад, номери телефонів, поштові індекси, навіть валюта * 1000 (зберігання) валюта div 1000 (пошук) швидше, ніж DECIMAL для порівняння.

Ozz


6

Покажчик чи ні, int набагато швидше (чим довший варчар, тим повільніше він стає).

Ще одна причина: показник на варчарному полі буде набагато більшим, ніж на int. Для великих таблиць це може означати сотні мегабайт (і тисячі сторінок). Це робить продуктивність набагато гіршою, оскільки для читання самого індексу потрібно багато зчитування диска.


3
Наприклад, 5 мільйонів записів "audi", невже індекс не може містити лише одну копію рядка "audi" та 5 мільйонів цілих чисел основного_кея? Чи різниця в розмірі дійсно була б такою великою, будь то vchar або ціла?
lulalala

Ви праві lulalala, але для стовпця, який міститиме випадкові рядки, відповідь досить справедлива.
Awais fiaz

4

Загалом, int буде швидшим. Чим довше варчар, тим повільніше він стає


3

Підказка: Якщо можливі значення для поля макіяжу будуть ніколи (або рідко) зміни, ви можете використовувати ENUM в якості компромісу. Він поєднує в собі хорошу швидкість з хорошою читабельністю.


1
Цікаво: Якою буде різниця швидкостей між ENUM та int?
googletorp

Чи має PostgresSQL enumтип даних? Я хоч і був специфічним для MySQL.
Роберт Мунтяну

У Postgres є ENUM, але я не думаю, що він реалізований зовсім так, як MySQL. postgresql.org/docs/current/static/datatype-enum.html
googletorp

2
Ефективність, ENUM має виконувати більш-менш те саме, що і int у полі пошуку, але як varchar у списку цілей (тому що він повинен передати весь рядок клієнту для відповідних рядків, а не лише int)
Magnus Hagander

1
Ось цікаве прочитання, чому НЕ використовувати enum в MySQL (просто щоб додати трохи палива до вогню: D)
Wilt

1

Якщо ввімкнути індексацію в будь-якому з полів, це буде швидше. Щодо вашого питання, я думаю, intце швидше, ніж varchar.


0

Дещо відносний. Так, INT буде швидше, але питання полягає в тому, чи це помітно у вашій ситуації. ВАРХАР - це лише невеликі слова чи довші тексти? і скільки рядків у таблиці? Якщо всього кілька рядків, швидше за все, вона буде повністю забудована в пам'яті (коли це вимагається часто), у такому випадку ви не помітите великої різниці. Тоді, звичайно, відбувається індексація, яка стає важливішою, коли таблиця росте. Використання SSD може бути швидше, ніж HD, з оптимізованими запитами. Також хороші дискові контролери іноді прискорюють запити> 10 разів. Це може залишити місце для простого використання VARCHAR, що полегшує читання та запит запитів (не потрібно писати складні приєднання) та пришвидшує розробку. Однак пуристи не погоджуються і завжди все нормалізують.

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