Дизайн бази даних для обробки 1 мільярда рядків і підрахунку


10

Ми отримуємо дані GPS в режимі реального часу зі швидкістю близько 5000 pr. хвилина (з 4 серверів TCP). Кожен сервер використовує єдине з'єднання для вставки даних та буферизує дані між вставками. Кожні 15 хвилин або близько того служба отримує ці дані та обробляє їх у поїздки. Після генерації подорожей фактичні дані GPS, як правило, не такі важливі, лише якщо користувач хоче бачити маршрут на карті.

Проблема полягає в тому, що, здається, база даних намагається не відставати від швидкості вставки даних. Іноді, коли навантаження збільшується, час вставки раптово різко збільшується (> 30 секунд), що, в свою чергу, дозволяє завантажувати більше даних, що, в свою чергу, призводить до більш великих вставок і більшої тривалості вставки.

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

Поточний дизайн

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

Дизайн столу

  • Id (PK, унікальний ідентифікатор)
  • DeviceId (FK, int)
  • PersonId (FK, int)
  • Ідентифікатор транспортного засобу (FK, int)
  • TokenId (FK, int)
  • UtcTime (ПК, дата2 (3))
  • Широта (плаваючий)
  • Довгота (поплавок)
  • Швидкість (smallint)
  • Заголовок (smallint)
  • Супутники (мініатюра)
  • IOData (варбінарний (100))
  • IgnitionState (tinyint)
  • UserInput (tinyint)
  • CreateTimeUtc (datetime2 (3))

Індекси

  • DeviceId_CreateTimeUtc_Desc
  • DeviceId_UtcTime_Desc (кластер)
  • PersonId_UtcTime_Desc
  • TokenId_UtcTime_Desc
  • VehicleId_UtcTime_Desc

Кожен тиждень наразі займає близько 10 ГБ, включаючи індекси, і в даний час в основній базі даних є близько 300 ГБ даних.

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

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

Машина являє собою 8-ядерний HP з 12 ГБ пам’яті, а диск, на якому розміщена основна база даних, працює на RAID 10.

Ідеї

  • Обмежте кількість даних, що зберігаються в основній базі даних, наприклад, максимум 1 місяць. Принаймні, це зробить базу даних більш керованою для резервного копіювання / відновлення, але чи можна очікувати покращення продуктивності, зробивши це?
  • Створіть 2 файли у групі файлів для поточних даних та розподіліть їх на 2 різні фізичні розділи
  • Створіть базові-ведені бази даних, що містять поточні дані, тому вставки та зчитування виконуються на різних базах даних
  • Помістіть файли поточних даних на SSD-диски (чи відображення дзеркальних даних має різницю в продуктивності з SSD-дисками?)

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


Коментарі не для розширеного обговорення; ця розмова була переміщена до чату .
Пол Білий 9

Відповіді:


8

5000 вставок в хвилину - це приблизно 83 вставки в секунду. З 5 індексів це 400 фізичних рядків, вставлених за секунду. Якщо завантаженість була в пам'яті, це не створювало б проблем навіть для найменших серверів. Навіть якщо це була вставка рядка за рядком, використовуючи найефективніший спосіб, про який я можу придумати. 83 тривіальних запиту в секунду просто не цікаві з точки зору процесора.

Напевно, ви пов'язані з диском. Ви можете перевірити це, переглянувши статистику очікування або STATISTICS IO.

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

Уявіть таблицю, куди ви лише фізично вставляєте її в кінці через постійно зростаючу клавішу. Робочим набором буде одна сторінка: остання. Це призведе до отримання послідовного вводу-виводу, а також ледачого письменника чи процесу пропуску записує "кінець" таблиці на диск.

Уявіть таблицю з випадковим чином розміщеними вставками (класичний приклад: ключ-орієнтир). Тут усі сторінки є робочим набором, оскільки для кожної вставки буде торкатися випадкова сторінка. ІО випадкові. Це найгірший випадок, коли мова йде про робочий набір.

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

Ви кажете, що дані поділяються на 10 ГБ на тиждень. Це хороша відправна точка, тому що робочий набір тепер обмежений 10 Гб (не зважаючи на будь-які прочитані вами читання). З 12 ГБ пам'яті сервера навряд чи всі відповідні сторінки можуть залишитися в пам'яті.

Якщо ви могли зменшити розмір щотижневих "розділів" або збільшити пам'ять сервера на трохи, ви, ймовірно, добре.

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

Тепер, навіть якщо всі читання та записи вписуються в пам'ять, у вас все одно можуть бути випадкові брудні сторінки, що промивають IO. Єдиний спосіб позбутися цього - записати на розташовані у своїх індексах позиції. Якщо ви взагалі можете перетворити свої індекси, щоб використовувати (більше) послідовні ключі, які б дуже допомогли.

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


1
@usr Дякую за дуже вичерпну та добре пояснену відповідь! Ми насправді обговорювали збільшення пам’яті сервера, не знаючи, який ефект від цього буде мати, - але тепер у нас справді є дуже вагома причина для цього :) Ви праві, що "SomeValue" частково рандомізує точки вставки - напевно, є близько 10000 ідентифікаторів пристрою. Щодо поетапної таблиці, чи є ваша пропозиція таблицею без будь-яких індексів, а потім завданням вставляти в основну таблицю кожні X хвилин?
сондергард

@usr Рег. Ваша пропозиція щодо перетворення кластерного індексу в послідовну, ми можемо додати автоматичний вкл. стовпчик ідентичності (ціле число) та змінити кластерний індекс на цей стовпець з єдиною метою - зберегти його послідовно? Це не було б унікальним для таблиць, але поки основний ключ, ми повинні бути добре.
сондергард

1
Якщо таблиця постановки невелика і ваші запити можуть працювати з нею, то вам не потрібно взагалі індексувати. Але ти міг би .; Однією з стратегій було б зробити CI у стовпчику ідентичності (як ви кажете). Це може творити чудеса, якщо КІ великий, а інші індекси малі. Оскільки записи CI тепер є послідовними, вони значно менше сприяють вашій проблемі. Ця стратегія є найбільш успішною, якщо є змістовна різниця в розмірах; Іншою ідеєю було б мати один стіл на день. Може зливатися щомісяця.
usr

Гаразд, ми розглядали створення стовпця ідентичності для CI, але, на жаль, це неможливо на розділеному представленні (не допускається стовпець ідентичності, немає значень за замовчуванням і всі стовпці повинні бути включені у вставку). Можливо, розділений вигляд був погано обраним дизайном, хоча його рекомендував консультант
sondergard

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