#sql-server #sql-server-2008 #data-compression #database-design
#sql-сервер #sql-сервер-2008 #сжатие #база данных-проектирование #sql-server-2008
Вопрос:
Мы используем SQL Server 2008 R2 Enterprise Edition.
Мы измеряем метеорологические данные из того, что мы называем MetMasts. По сути, это мачта с большим количеством оборудования; анемометры (для измерения скорости ветра) в разных положениях на мачте, термометры и давление воздуха. Мы измеряем каждую секунду.
И это занимает слишком много места на диске. Следующее поколение этого оборудования будет генерировать более 10 ГБ в год каждое. И у нас их будет более 1000.
Текущий дизайн таблицы выглядит примерно так:
CREATE TABLE #MetMast (
MetMastID INT NOT NULL IDENTITY(1,1),
MetMastName NVARCHAR(100),
CountryID INT,
InstallDate DATE
)
CREATE TABLE #MetMastData (
MetMastDataID BIGINT NOT NULL IDENTITY(1,1),
MetMastID INT NOT NULL,
MeasuredAt DATETIME2(0) NOT NULL,
Temperature REAL NULL,
WindSpeedAt10m REAL NULL,
WindSpeedAt30m REAL NULL,
AirPressure REAL NULL,
OneHundredMoreColumns VARCHAR(200),
CONSTRAINT PK_MetMastData PRIMARY KEY CLUSTERED
(
MetMastID ASC,
MeasuredAt ASC
))
WITH (DATA_COMPRESSION = ROW)
-- ON a file group, with table partitioning
ALTER TABLE #MetMastData WITH NOCHECK ADD CONSTRAINT FK_MetMast_MetMastID FOREIGN KEY (#MetMast) REFERENCES #MetMast(MetMastID)
Данные записываются один раз, считываются много-много раз.
Мы используем его в нашем хранилище данных, где типичным вопросом было бы: Подсчитайте, во сколько раз разница в 2 м / с между скоростями ветра 10 м и 30 м при температуре выше 20 градусов на метамачту.
SELECT MetMastId, COUNT_BIG(*) FROM #metMastData
WHERE temperature>20 AND ABS(WindSpeedAt10m-WindSpeedAt30m) >2
GROUP BY MetMastID
В будущем будет допущена небольшая потеря данных.
Здесь мы говорим о сжатии данных с потерями. Я знаю, что нам придется определить допустимую погрешность для каждого из полей, например, в 1%, если мы измеряем с точностью 10%.
Это работало для звуковых файлов (MP3 довольно большой), так что это могло бы сработать и для нас.
Но как это делается?
На какой дизайн стола мне следует обратить внимание?
Как мне начать работу со сжатием данных с потерями в таблицах базы данных?
С наилучшими пожеланиями,
Henrik Staun Poulsen
Ответ №1:
Для каждой из ваших точек данных учитывайте точность, которую вам необходимо сохранить.
REAL занимает четыре байта для каждой строки. Если бы вы могли удалить все десятичные разряды для скорости ветра, вы, вероятно, могли бы использовать tinyint (1 байт, 1-255). Учитывая, что вам, скорее всего, нужна некоторая точность, вы могли бы вместо этого использовать smallint и умножить фактическое значение на 100:
150,55 m/s = 15055
3,67 m/s = 367
Это сэкономило бы вам два байта на строку и сохранило бы некоторую точность, хотя и с потерей в какой-то момент. Поскольку кажется, что у вас будет довольно много таких столбцов, экономия в 2 байта на столбец составит довольно много.
У вас есть 8-байтовый bigint для вашего MetMastDataID. Необходимо ли это? Не будут ли все запрашиваться MetMastID и MeasuredAT? Удаление этого сэкономит вам 8 байт. Однако это приведет к фрагментации, поскольку ваш кластеризованный ключ больше не будет последовательным, поэтому потребуется дефрагментация. Поскольку это звучит как архивная / OLAP-система, это не должно быть большой проблемой.
РЕДАКТИРОВАТЬ: Я только что понял, что вы не кластеризованы в MetMastDataID, поэтому фрагментация с этого момента не изменится. Тогда вопрос в том, используете ли вы когда-нибудь MetMastDataID для чего-либо?
Кроме того, если вы сможете избежать всех столбцов переменной длины, это сэкономит вам 2 байта 2 байта на столбец переменной длины накладных расходов на запись в строке, не включая сами фактические данные переменной длины.
Комментарии:
1. Хэджей Марк, большое тебе спасибо за твой ответ, который созвучен Р. Кимбаллу; поставь свой факт на диету. Мы сделали это, насколько смогли. Но большая часть этих данных меняется не очень часто; температуры измеряются только каждые 42 секунды. Таким образом, здесь должно быть много возможностей для улучшения.
2. Вы упомянули, что температуры измеряются только каждые 42 секунды — означает ли это, что вы записываете данные, в целом, только каждые 42 секунды, или вы записываете другие данные с меньшим интервалом и, таким образом, сохраняете одно и то же значение температуры несколько раз? В случае, если вы сохраняете измерение каждую секунду, это означает, что у вас будет 41 идентичное значение для температуры — в этом случае имело бы смысл использовать эти столбцы как разреженные. Каждый 42-й имеет значение, а остальные равны НУЛЮ, что указывает на то, что они равны последнему измеренному значению.
3. Кстати, я вижу, что вы тоже из Орхуса — дайте мне знать, если вы заинтересованы в организации автономного просмотра этого — разумеется, бесплатно. Это интересный случай, я бы хотел более тщательно рассмотреть его 🙂
4. Привет, Марк, Да, это вариант, о котором мы думали. Мы немного обеспокоены получением этих данных впоследствии. 42 не является фиксированным числом, просто таким образом легко объяснить передискретизацию. Благодарим вас за предложение о просмотре в автономном режиме. Мы проводим следующую встречу sqlsug, если вы являетесь участником, мы сможем поговорить немного подробнее. (к сожалению, не так много без NDA)
5. Я почти уверен, что буду на собрании sqlsug, тогда cya там 🙂
Ответ №2:
Сжатие с потерями основано на физических возможностях человека определять разницу на глаз или слух. Примерами являются сжатие в формате Mp3 или JPEG с потерями. В вашем случае такой вид сжатия с потерями не имеет смысла, потому что вы работаете с цифрами, а не с аудио / видеоданными. Для реализации сжатия без потерь вы можете использовать функцию CLR.Пример здесь:http://www.codeproject.com/KB/database/blob_compress.aspx.
Комментарии:
1. Привет, Dalex, теперь я понимаю, что нам нужно указать наши требования для каждого поля. Но это должно быть возможно. Ветер измеряется с точностью -5%, поэтому было бы приемлемо добавить .5%, если мы улучшим ситуацию с хранением. Спасибо за ссылку, возможно, мы сможем использовать некоторые из них.