Здравствуйте, SergeyBi, Вы писали:
W>>Так какая СУБД? Для некоторых можно оптимизировать... SB>ms sql 2000
Тогда надо написать табличную UDF, строящую набор временных отсчетов, и получить результат одним запросом. Не знаю насчет сложности, но скорость должна быть больше, чем расчет на клиенте.
Здравствуйте, wildwind, Вы писали:
W>Здравствуйте, SergeyBi, Вы писали:
W>>>Так какая СУБД? Для некоторых можно оптимизировать... SB>>ms sql 2000
W>Тогда надо написать табличную UDF, строящую набор временных отсчетов, и получить результат одним запросом. Не знаю насчет сложности, но скорость должна быть больше, чем расчет на клиенте.
сложность <=> время
не знаю с чего бы скорочть была больше чем на клиенте,
если на клиенте будет работать более быстрый алгоритм,
например такой как привел Nev0
Здравствуйте, wildwind, Вы писали:
W>Здравствуйте, pivoo, Вы писали:
P>>не знаю с чего бы скорочть была больше чем на клиенте,
W>Например с того, что вся туча данных не будет бегать по сети.
Здравствуйте, pivoo, Вы писали:
P>Здравствуйте, wildwind, Вы писали:
W>>Здравствуйте, pivoo, Вы писали:
P>>>не знаю с чего бы скорочть была больше чем на клиенте,
W>>Например с того, что вся туча данных не будет бегать по сети.
Это уже зависит от предназначения приложения. Может данные все-равно надо пересылать не только для этой цели?
P>хороший аргумент, возможно это и так
А почему бы не использовать более быстрый алгоритм на сервере + повесить на него какой-нибудь кэш и пересылать только результат?
Здравствуйте, Nev0, Вы писали:
N>А почему бы не использовать более быстрый алгоритм на сервере + повесить на него какой-нибудь кэш и пересылать только результат?
согласен, использование неоптимального алгоритма меня и смущало, НО
при выборе из 2 вариантов
1-ый — неоптимальный алгоритм выполняющийся на стороне сервера, без пересылки "тучи данных"
2-ой — быстрый алгоритм на стороне клиента, но с необходимостью получения большой выборки (а она может быть и очень большая)
я даже не знаю какому из них отдал бы предпочтение
>N Это уже зависит от предназначения приложения. Может данные все-равно надо пересылать не только для этой цели?
сомневаюсь, что есть такие задачи, где все данные (необходимые алгоритму) передавались бы для других целей, просто не могу вообразить
Здравствуйте, Nev0, Вы писали:
N>А почему бы не использовать более быстрый алгоритм на сервере + повесить на него какой-нибудь кэш и пересылать только результат?
Здравствуйте, wildwind, Вы писали:
W>Здравствуйте, Nev0, Вы писали:
N>>А почему бы не использовать более быстрый алгоритм на сервере + повесить на него какой-нибудь кэш и пересылать только результат?
W>Для этого и предназначены хранимые процедуры.
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
if object_id('GetMaxSynchTalk_Iter') is not null drop proc GetMaxSynchTalk_Iter
Go
Create proc GetMaxSynchTalk_Iter
@Start datetime = null,
@End datetime = null
as
begin
set dateformat dmy
Declare @MaxTalk dec(15,0), @Counter dec(15,0)
select @Start=isnull(@Start,(select Min(StartMoment) from History where StartMoment is not Null and StopMoment is not null))
select @End=isnull(@End,(select Max(StartMoment) from History where StartMoment is not Null and StopMoment is not null))
select StartMoment T, 'Start' F into #X1
from History -- Startwhere StartMoment between @Start and @End
and StartMoment is not Null and StopMoment is not Null
select StopMoment T, 'Stop' F into #X2
from History -- Stopwhere StartMoment between @Start and @End
and StartMoment is not Null and StopMoment is not Null
select a.* into #Result from
( select T, F from #x1
union all
select T, F from #x2 ) as a
order by a.T
set @MaxTalk=0
set @Counter=0
Declare @T datetime, @F varchar(5)
Declare CR cursor
for select T, F
from #Result order by T
Open CR
FETCH NEXT FROM CR INTO @T, @F
WHILE @@FETCH_STATUS = 0
BEGIN
if @F='Start'
select @Counter= @Counter+1.0
else
select @Counter=@Counter-1.0
if @Counter>@maxTalk
select @MaxTalk= @Counter
FETCH NEXT FROM CR INTO @T, @F
END
CLOSE CR
DEALLOCATE CR
select @MaxTalk MaxSynchTalk
end
GO
set dateformat dmy
Exec GetMaxSynchTalk_Iter '18.07.2005', '22.07.2005'
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
Да, примерно так.
Полагаю, можно упростить. Нужную выборку можно получить одним запросом, соединив History с любым набором из двух строк. Типа такого
select ev.Event,
case ev.Event
when 'Start' then h.StartMoment
else h.StopMoment
end as Moment
from History h
join (select 'Start' as Event union select 'Stop') ev
where h.StartMoment between ...
order by Moment, Event desc
Не уверен, что нет ошибок в синтаксисе (T-SQL не родной для меня), но идея надеюсь понятна.
Так как точность datetime в SQL Server намного больше секунды, то ситуацию, когда в один момент начались 3 разговора и 2 закончились, можно не обрабатывать. Но даже если такое случится, order by предохранит от ошибки.
Здравствуйте, SergeyBi, Вы писали:
SB>Столкнулся по работе с реальной задачей, которую пока не совсем знаю как оптимально решить.
SB>Ведется запись телефонных разговоров в call center. Есть таблица hystory в которую записываются данные о разговорах. SB>Среди прочих полей там есть время начала и окончания разговора. Телефонов, разговоры которых записываются довольно много. SB>Задача: определить максимальное количество одновременных разговоров за некоторый период времени(например 3 месяца). SB>Количество разговоров в неделю ~70 тыс.
SB>У таблицы есть поле ID, которое проиндексировано. И записи с большей ID соответствует большее(точнее не меньшее) время начала разговора.
SB>Заранее спасибо за варианты.
Я не знаю можно ли это организовать в хранимой процедуре, я вообще с SQL жружу на уровне простых запросов... но есть такое решение...
1 день — это всего 86 400 секунд
1 месяй — это всего 2 678 400 секунд
1 год — это всего 32 140 800 секунд
теперь зачем все это надо
Давайте будем считать что точность полей начала и конца разговора ограничего 1 секудой...
А теперь алгоритм сложность простой до умопомрачения.
пусть T время начала разговора от начальной даты, а Е соответсвенно конец этого разговора.А BUFFER это просто массив signed char( или signed short — для очень большого центра ). Далее все просто
BUFFER[T] ++;
BUFFER[E] --;
Далее просто идем от начала и делаем если BUFFER[I] != 0, А += BUFFER[I] и смотрим максимумы, заодно пицем новую таблицу где 1-е поле время а 2-е величина изменения количества звонков. Сохранив данную таблицу далее имеет смысл только дописывать ее по мере необходимости пересчитывая остатки.
В итоге все считается быстро потому как если сохранять результаты придеться пересчитывать только то что произошло за последнее время.
Вообщем примерно так.
P.S. при реализации учесть что нужно ввести компенсацию при построении таблицы,если на второй стади результат становиться отрицательным, то уже к найденному максимуму надо прибавить это дело но со знаком +
Памяти нада только на первом прощете который делается 1 раз да и то как я понимаю 64 мега хватит