Обычно, Вы получили бы RST, если Вы делаете завершение, которое не задерживается (т.е. в котором данные могут быть отброшены стеком, если это не было отправлено и ACK'd), и нормальный FIN, если Вы позволяете близко к, задерживаются (т.е. завершение ожидает данных в пути, чтобы быть ACK'd).
, Возможно, все, что необходимо сделать, установлено сокет для задержаний так, чтобы Вы удалили состояние состязания между не непрекращающимся завершением, сделанным на сокете и прибытием ACKs?
Очевидно, что количество одновременных пользователей изменяется только тогда, когда пользователь либо начинает, либо завершает период, поэтому достаточно определить количество одновременных пользователей во время начала и окончания. Итак, повторное использование тестовых данных, предоставленных Ремусом (спасибо, Ремус):
DECLARE @Table TABLE
(
UserId int,
StartedOn datetime,
EndedOn datetime
);
insert into @table (UserId, startedOn, EndedOn)
select 1, '2009-7-12 14:01', '2009-7-12 15:01'
union all select 2, '2009-7-12 14:30', '2009-7-12 14:45'
union all select 3, '2009-7-12 14:47', '2009-7-12 15:30'
union all select 4, '2009-7-12 13:01', '2009-7-12 17:01'
union all select 5, '2009-7-12 14:15', '2009-7-12 18:01'
union all select 6, '2009-7-12 11:01', '2009-7-12 19:01'
union all select 1, '2009-7-12 16:07', '2009-7-12 19:01';
SELECT MAX(ConcurrentUsers) FROM(
SELECT COUNT(*) AS ConcurrentUsers FROM @table AS Sessions
JOIN
(SELECT DISTINCT StartedOn AS ChangeTime FROM @table
) AS ChangeTimes
ON ChangeTime >= StartedOn AND ChangeTime < EndedOn
GROUP BY ChangeTime
) AS ConcurrencyAtChangeTimes
-------
5
Кстати, использование DISTINCT само по себе не является ошибкой - только злоупотребление DISTINCT. DISTINCT - это просто инструмент, Обратите внимание, что в вопросе не упоминается производительность.
Если бы вопросы были следующие: «каков самый быстрый способ определить максимальный параллелизм, если данные хранятся в SQL Server», я бы дал другой ответ, примерно так:
Рассмотрите следующие альтернативы
Если бы вопрос был «каков самый быстрый способ определить максимальный параллелизм с помощью запроса T-SQL», я бы, вероятно, вообще не ответил. Причина: если мне нужна была действительно хорошая производительность,
Я попробовал решение Алекса Кузнецова, но результат был 49: (
Мое решение:
/* Create temporary table and set all dates into 1 column,
so we can sort by this one column */
DECLARE @tmp table (
Dates datetime,
IsStartedDate bit )
INSERT INTO @tmp
SELECT StartedOn, 1 FROM stats
UNION ALL
SELECT EndedOn, 0 FROM stats
DECLARE @currentlogins int, @highestlogins int, @IsStartedDate bit;
SET @currentlogins = 0;
SET @highestlogins = 0;
DECLARE tmp_cursor CURSOR FOR
SELECT IsStartedDate FROM @tmp
ORDER BY Dates ASC
OPEN tmp_cursor
/* Step through every row, if it's a starteddate increment @currentlogins else decrement it
When @currentlogins is higher than @highestlogins set @highestlogins to the new highest value */
FETCH NEXT FROM tmp_cursor
INTO @IsStartedDate
WHILE @@FETCH_STATUS = 0
BEGIN
IF (@IsStartedDate = 1)
BEGIN
SET @currentlogins = @currentlogins + 1;
IF (@currentlogins > @highestlogins)
SET @highestlogins = @currentlogins;
END
ELSE
SET @currentlogins = @currentlogins - 1;
FETCH NEXT FROM tmp_cursor
INTO @IsStartedDate
END
CLOSE tmp_cursor
DEALLOCATE tmp_cursor
SELECT @highestlogins AS HighestLogins
Вы можете упорядочить все события по дате и вычислить текущую совокупность текущих пользователей, вошедших в систему:
DECLARE @Table TABLE
(
UserId int,
StartedOn datetime,
EndedOn datetime
);
insert into @table (UserId, startedOn, EndedOn)
select 1, '2009-7-12 14:01', '2009-7-12 15:01'
union all select 2, '2009-7-12 14:30', '2009-7-12 14:45'
union all select 3, '2009-7-12 14:47', '2009-7-12 15:30'
union all select 4, '2009-7-12 13:01', '2009-7-12 17:01'
union all select 5, '2009-7-12 14:15', '2009-7-12 18:01'
union all select 6, '2009-7-12 11:01', '2009-7-12 19:01'
union all select 1, '2009-7-12 16:07', '2009-7-12 19:01';
with cte_all_events as (
select StartedOn as Date
, +1 as Users
from @Table
union all
select EndedOn as Date
, -1 as Users
from @Table),
cte_ordered_events as (
select Date
, Users
, row_number() over (order by Date asc) as EventId
from cte_all_events)
, cte_agg_users as (
select Date
, Users
, EventId
, (select sum(Users)
from cte_ordered_events agg
where agg.EventId <= e.EventId) as AggUsers
from cte_ordered_events e)
select * from cte_agg_users
2009-07-12 11:01:00.000 1 1 1
2009-07-12 13:01:00.000 1 2 2
2009-07-12 14:01:00.000 1 3 3
2009-07-12 14:15:00.000 1 4 4
2009-07-12 14:30:00.000 1 5 5
2009-07-12 14:45:00.000 -1 6 4
2009-07-12 14:47:00.000 1 7 5
2009-07-12 15:01:00.000 -1 8 4
2009-07-12 15:30:00.000 -1 9 3
2009-07-12 16:07:00.000 1 10 4
2009-07-12 17:01:00.000 -1 11 3
2009-07-12 18:01:00.000 -1 12 2
2009-07-12 19:01:00.000 -1 13 1
2009-07-12 19:01:00.000 -1 14 0
После того, как вы это сделаете, определение максимального количества одновременных сеансов будет тривиальным. Как видите, у вас есть два момента, когда у вас было 5 пользователей: в 14:30 (когда пользователь 2 вошел в систему) и в 14:47 (когда пользователь 3 вошел в систему). Просто замените последний запрос, который выбирает из CTE, чтобы получить фактический максимум:
select top(1) AggUsers
from cte_agg_users
order by AggUsers desc
Это решение использует CTE, поэтому оно будет работать только с SQL 2k5, если вы все еще используете SQL 2000, вам придется переписать его, используя производные таблицы вместо CTE.
Наивный подход:
Вы можете проверить, вошел ли в систему в настоящее время другой пользователь b, когда пользователь a входит в систему с
a.StartedOn BETWEEN b.StartedOn AND b.EndedOn
. И кто-то должен быть «последним входом в систему» для набора «наиболее одновременных пользователей».
Если вы теперь просмотрите все записи (как a) и проверьте, сколько других пользователей (b) вошли в систему в то время, а затем упорядочите список (desc), первым результатом будет максимальное количество одновременно работающих пользователей.
SELECT
a.id, a.UserId, a.StartedOn, a.EndedOn,
(
SELECT
Count(*)
FROM
logons as b
WHERE
a.StartedOn BETWEEN b.StartedOn AND b.EndedOn
) as c
FROM
logons as a
ORDER BY
c desc
А теперь прочтите Ошибки разработки баз данных, сделанные разработчиками приложений , чтобы увидеть, насколько это неэффективно (или даже неправильно); -)
например, у вас есть большая временная таблица, с которой работает порядок, без какого-либо индекса, чтобы помочь серверу sql.
(и, кстати, я тестировал это с MySQL, потому что сейчас у меня нет SQL-сервера под рукой)
Я выполнил работу, используя целые числа, а не поля даты и времени, но я считаю, что следующий фрагмент sql дает вам то, что вы хотите.
По сути, я сравнивал дату начала и окончания каждого пользователя друг с другом, используя самостоятельное соединение. Если пользователь A был запущен раньше или одновременно с пользователем B, И пользователь B был запущен до или в то же время, что и пользователь A, они работают одновременно. Таким образом, я нашел пользователя с максимальным количеством одновременных пользователей (и добавил 1 для себя, поскольку я исключил их из самоподключения).
Я заметил, что у вас есть несколько строк для каждого пользователя. Обратите внимание, что в приведенном ниже sql предполагается, что один и тот же пользователь не может запускать несколько экземпляров одновременно (одновременно). Если это предположение не выполняется, я надеюсь, что у вас есть дополнительный столбец, уникальный для каждой строки. Используйте этот столбец вместо UserId во всей подпрограмме sql.
Я очень близко тебя подобрал. Надеюсь, это поможет. Удачи.
DECLARE @Table TABLE
(
UserId int,
StartedOn int,
EndedOn int
)
Insert Into @Table
Select 1, 1, 3
union
Select 2, 2, 4
union
Select 3, 3, 5
union
Select 4, 4, 6
union
Select 5, 7, 8
union
Select 6, 9, 10
union
Select 7, 9, 11
union
Select 8, 9, 12
union
Select 9, 10, 12
union
Select 10, 10, 13
--Select * from @Table
Select
A.UserId,
Count(B.UserId) + 1 as 'Concurrent Users'
FROM @Table A, @Table B
WHERE A.StartedOn <= B.StartedOn
AND B.StartedOn <= A.EndedOn
AND A.UserId != B.UserId
Group By A.UserId
Order By Count(B.UserId) Desc
вы выполняете самостоятельное присоединение к этому столу