/// <summary>
        /// Загружает подлежащие сжатию записи.
        /// </summary>
        /// <param name="compressSetting">Настройка сжатия статистики.</param>
        /// <returns>Список записей статистики, загруженный из БД.</returns>
        private List <StatisticsRecord> LoadRecordsForCompression(StatisticsCompressionSetting compressSetting)
        {
            // Сжиматься должны интервалы старше этого времени.
            var timeLimit = AddTimeUnitsToDate(_timeService.Now, compressSetting.StatisticsAgeUnits, -compressSetting.StatisticsAgeCount);

            // После сжатия должно получиться целое число новых интервалов, поэтому вычисляем точный конец сжимаемого промежутка времени.
            var timeEnd = GetStartOfInterval(timeLimit, compressSetting.CompressTo);

            // Формирование основного условия для выборки.
            // Выбираются только записи, интервал которых меньше целевого.
            var recordsQuery = _dataService.Query <StatisticsRecord>(StatisticsRecord.Views.CompressView);
            var oneSecond    = StatisticsInterval.OneSecond;
            var tenSeconds   = StatisticsInterval.TenSeconds;
            var oneMinute    = StatisticsInterval.OneMinute;
            var fiveMinutes  = StatisticsInterval.FiveMinutes;
            var tenMinutes   = StatisticsInterval.TenMinutes;
            var hour         = StatisticsInterval.Hour;
            var day          = StatisticsInterval.Day;
            var month        = StatisticsInterval.Month;
            var quarter      = StatisticsInterval.Quarter;
            var year         = StatisticsInterval.Year;

            switch (compressSetting.CompressTo)
            {
            case StatisticsInterval.OneSecond:
                recordsQuery = recordsQuery.Where(x => false);
                break;

            case StatisticsInterval.TenSeconds:
                recordsQuery = recordsQuery.Where(x => x.StatisticsInterval == oneSecond || x.StatisticsInterval == tenSeconds);
                break;

            case StatisticsInterval.OneMinute:
                recordsQuery = recordsQuery.Where(x => x.StatisticsInterval == oneSecond || x.StatisticsInterval == tenSeconds || x.StatisticsInterval == oneMinute);
                break;

            case StatisticsInterval.FiveMinutes:
                recordsQuery = recordsQuery.Where(x => x.StatisticsInterval == oneSecond || x.StatisticsInterval == tenSeconds || x.StatisticsInterval == oneMinute || x.StatisticsInterval == fiveMinutes);
                break;

            case StatisticsInterval.TenMinutes:
                recordsQuery = recordsQuery.Where(x => x.StatisticsInterval == oneSecond || x.StatisticsInterval == tenSeconds || x.StatisticsInterval == oneMinute || x.StatisticsInterval == fiveMinutes || x.StatisticsInterval == tenMinutes);
                break;

            case StatisticsInterval.HalfAnHour:
                recordsQuery = recordsQuery.Where(x => x.StatisticsInterval != hour && x.StatisticsInterval != day && x.StatisticsInterval != month && x.StatisticsInterval != quarter && x.StatisticsInterval != year);
                break;

            case StatisticsInterval.Hour:
                recordsQuery = recordsQuery.Where(x => x.StatisticsInterval != day && x.StatisticsInterval != month && x.StatisticsInterval != quarter && x.StatisticsInterval != year);
                break;

            case StatisticsInterval.Day:
                recordsQuery = recordsQuery.Where(x => x.StatisticsInterval != month && x.StatisticsInterval != quarter && x.StatisticsInterval != year);
                break;

            case StatisticsInterval.Month:
                recordsQuery = recordsQuery.Where(x => x.StatisticsInterval != quarter && x.StatisticsInterval != year);
                break;

            case StatisticsInterval.Quarter:
                recordsQuery = recordsQuery.Where(x => x.StatisticsInterval != year);
                break;

            case StatisticsInterval.Year:
                recordsQuery = recordsQuery.Where(x => true);
                break;

            default:
                throw new Exception("Неизвестный интервал статистики: " + compressSetting.CompressTo.ToString());
            }

            recordsQuery = recordsQuery.Where(x => x.StatisticsSetting.__PrimaryKey == compressSetting.StatisticsSetting.__PrimaryKey && x.To <= timeEnd).OrderBy(x => x.Since);
            if (MaxRecordsForOneCompression > 0)
            {
                recordsQuery = recordsQuery.Take(MaxRecordsForOneCompression);
            }

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            var dobjs = recordsQuery.ToList();

            stopwatch.Stop();
            long time = stopwatch.ElapsedMilliseconds;

            _statisticsService.NotifyAvgTimeSql(compressSetting.StatisticsSetting.Subscription, (int)time, "DefaultStatisticsCompressorService.LoadRecordsForCompression() load StatRecords.");

            return(dobjs);
        }
        private List <StatisticsRecord> CompressRecords(IEnumerable <StatisticsRecord> records, StatisticsCompressionSetting compressSetting)
        {
            // Формирование списка новых сжатых записей.
            var compressedRecords = records
                                    .GroupBy(x => GetStartOfInterval(x.Since, compressSetting.CompressTo))
                                    .Select(x =>
                                            new StatisticsRecord()
            {
                StatisticsSetting = compressSetting.StatisticsSetting,
                Since             = x.Key,
                To = AddStatIntervalToDate(x.Key, compressSetting.CompressTo, 1),
                StatisticsInterval = compressSetting.CompressTo,
                SentCount          = x.Sum(y => y.SentCount),
                ReceivedCount      = x.Sum(y => y.ReceivedCount),
                ErrorsCount        = x.Sum(y => y.ErrorsCount),
                UniqueErrorsCount  = x.OrderBy(y => y.Since).Last().UniqueErrorsCount,
                QueueLength        = x.OrderBy(y => y.Since).Last().QueueLength,
                SentAvgTime        = x.Sum(y => y.SentAvgTime) / x.Count(),
                QueryAvgTime       = x.Sum(y => y.QueryAvgTime) / x.Count(),
                ConnectionCount    = x.OrderBy(y => y.Since).Last().ConnectionCount,
            })
                                    .ToList();

            return(compressedRecords);
        }
        public void TestPartCompression()
        {
            foreach (var dataService in DataServices)
            {
                // Arrange.
                var statSetting        = new StatisticsSetting();
                var compressionSetting = new StatisticsCompressionSetting()
                {
                    StatisticsSetting  = statSetting,
                    CompressTo         = StatisticsInterval.Hour,
                    StatisticsAgeCount = 1,
                    StatisticsAgeUnits = TimeUnit.Minute,
                    NextCompressTime   = DateTime.Now,
                };
                var dataObjects = new DataObject[100];
                var date        = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour - 1, 0, 0, 0);
                for (int i = 0; i < 100; i++)
                {
                    dataObjects[i] = new StatisticsRecord()
                    {
                        Since = date.AddMinutes(i),
                        To    = date.AddMinutes(i + 1),
                        StatisticsInterval = StatisticsInterval.OneMinute,
                        SentCount          = 1,
                        StatisticsSetting  = statSetting,
                    };
                }

                var counter         = 0;
                var mockTimeService = new Mock <IStatisticsTimeService>();
                mockTimeService
                .Setup(ts => ts.Now)
                .Callback(() =>
                {
                    counter++;
                    if (counter == 5)
                    {
                        throw new Exception("As if something went wrong.");
                    }
                }).Returns(DateTime.Now);

                dataService.UpdateObject(statSetting);
                dataService.UpdateObject(compressionSetting);
                dataService.UpdateObjects(ref dataObjects);

                var component = new DefaultStatisticsCompressorService(
                    dataService,
                    mockTimeService.Object,
                    GetMockLogger(),
                    GetMockStatisticsService())
                {
                    CompressionPeriod           = 1000,
                    MaxRecordsForOneCompression = 50,
                };

                // Act.
                Act(component);

                // Assert.
                var statRecords = dataService.Query <StatisticsRecord>(StatisticsRecord.Views.CompressView)
                                  .OrderBy(r => r.Since)
                                  .ToArray();
                var compressedRecord   = statRecords.First();
                var unCompressedRecord = statRecords.Skip(1).First();

                Assert.Equal(41, statRecords.Count());
                Assert.Equal(60, compressedRecord.SentCount);
                Assert.Equal(StatisticsInterval.Hour, compressedRecord.StatisticsInterval);
                Assert.Equal(StatisticsInterval.OneMinute, unCompressedRecord.StatisticsInterval);
            }
        }