Оптимальное устройство хранения данных структуры данных для быстрого поиска и персистентности

Сценарий

У меня есть следующие методы:

public void AddItemSecurity(int itemId, int[] userIds)
public int[] GetValidItemIds(int userId)

Первоначально я думаю устройство хранения данных на форме:

itemId -> userId, userId, userId

и

userId -> itemId, itemId, itemId

AddItemSecurity на основе того, как я получаю данные от третьего лица API, GetValidItemIds то, как я хочу использовать его во времени выполнения.

Существует потенциально 2 000 пользователей и 10 миллионов объектов. Идентификатор объекта находится на форме: 2007123456, 2010001234 (10 цифр, где сначала четыре представляют год).

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

Я пытаюсь думать о том, как я должен сохранить это оптимальным способом. Предпочтительно на диске (с кэшированием), но я хочу код, удобный в сопровождении и чистый.

Если идентификатор объекта запустился в 0, я думал о создании массива байтов длина MaxItemId / 8 для каждого пользователя и набора истинный/ложный бит, если объект присутствовал или нет. Это ограничило бы длину массива до немного более чем 1 МБ на пользователя и дало бы быстрые поиски, а также простой способ обновить список на пользователя. Путем сохранения этого как Файлов С отображенной памятью с платформой.Net 4 я думаю, что получил бы достойное кэширование также (если машина имеет достаточно RAM), не реализовывая кэширование логики сам. При парсинге идентификатора, снятии года и хранилища массив в год мог быть решением.

ItemId-> UserId [] список может быть сериализирован непосредственно к диску и чтению-записи с нормальным FileStream для сохранения списка и разности это, когда существуют изменения.

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

Вопрос

Я должен продолжить испытывать этот подход или являюсь там другими путями, которые должны быть исследованы также? Я думаю, что SQL-сервер не будет работать достаточно быстро, и он дал бы издержки (по крайней мере, если он размещается на другом сервере), но мои предположения могли бы быть неправильными. Любая мысль или понимание по вопросу ценятся. И я хочу попытаться решить его, не добавляя слишком много аппаратных средств :)

[Обновите 31.03.2010]

Я теперь протестировал с SQL-сервером 2008 при следующих условиях.

  • Таблица с двумя столбцами (идентификатор пользователя, itemid) оба - Интервал
  • Кластерный индекс на двух столбцах
  • Добавленный ~800.000 объекта для 180 пользователей - Общее количество 144 миллионов строк
  • Выделенный поршень на 4 ГБ для SQL-сервера
  • Двухъядерный ноутбук на 2.66 ГГц
  • Диск SSD
  • Используйте SqlDataReader для чтения всего itemid's в Список
  • Цикл по всем пользователям

Если я выполняю один поток, он составляет в среднем на 0,2 секундах. Когда я добавляю второй поток, он подходит к 0,4 секундам, который все еще в порядке. Оттуда на результатах уменьшаются. Добавление третьего потока приносит много запросов до 2 seonds. Дальше распараллеливают, до 4 секунд, пятая часть скачки некоторые запросы до 50 секунд.

ЦП настилает крышу, в то время как это продолжается, даже на одном потоке. Мое тестовое приложение берет некоторых из-за быстрого цикла и sql остальные.

Который приводит меня к заключению, что это не масштабируется очень хорошо. По крайней мере, не на моих протестированных аппаратных средствах. Есть ли способы оптимизировать базу данных, сказать хранение массива интервала на пользователя вместо одной записи на объект. Но это мешает удалять объекты.

[2010-03-31 # 2 обновления]

Я сделал быстрый тест с теми же данными, поместив его как биты в файлах с отображенной памятью. Это работает намного лучше. Шесть потоков приводят ко временам доступа между 0,02 с и 0,06 с. Просто память связывается. Отображаемые файлы были отображены одним процессом и получены доступ шестью другими одновременно. И поскольку основа sql взяла 4 ГБ, файлы на диске взяли 23 МБ.

8
задан Mikael Svenson 6 April 2010 в 09:47
поделиться

3 ответа

После долгих испытаний я закончил тем, что использовал файлы с отображением памяти, пометив их разреженным битом (NTFS), используя код из NTFS Sparse Files with C # .

В Википедии есть объяснение того, что такое разреженный файл .

Преимущества использования разреженного файла заключаются в том, что мне не нужно заботиться о том, в каком диапазоне находятся мои идентификаторы. Если я напишу идентификаторы только между 2006000000 и 2010999999, файл будет выделять только 625 000 байт со смещения 250 750 000 в файле. . Все пространство до этого смещения не распределяется в файловой системе. Каждый идентификатор хранится в файле как установленный бит.Вроде как битовый массив. И если последовательность id внезапно изменится, то она будет размещена в другой части файла.

Чтобы узнать, какие идентификаторы установлены, я могу выполнить вызов ОС, чтобы получить выделенные части разреженного файла, а затем я проверяю каждый бит в этих последовательностях. Также очень быстро проверяется, установлен ли конкретный идентификатор. Если он выходит за пределы выделенных блоков, значит, его нет, если он попадает внутрь, это просто чтение одного байта и проверка битовой маски, чтобы увидеть, установлен ли правильный бит.

Итак, для конкретного сценария, когда у вас много идентификаторов, которые вы хотите проверить с максимальной скоростью, это самый оптимальный способ, который я нашел до сих пор.

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

3
ответ дан 6 December 2019 в 00:06
поделиться

Я действительно думаю, что вы должны попробовать хорошую базу данных, прежде чем принимать решение. Что-то вроде этого будет сложно поддерживать в долгосрочной перспективе. Ваша база пользователей на самом деле довольно мала. SQL Server должен быть в состоянии справиться с тем, что вам нужно, без каких-либо проблем.

1
ответ дан 6 December 2019 в 00:06
поделиться

2000 пользователей - это не так уж и плохо, но с 10 миллионами связанных элементов вам действительно стоит подумать о том, чтобы поместить их в базу данных. БД делают все необходимое для хранения, сохранения, индексации, кеширования и т. Д., И они работают очень хорошо.

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

0
ответ дан 6 December 2019 в 00:06
поделиться