Хранение статуса платежа в высоконагруженной базе
От: PetrovichForever Россия  
Дата: 28.03.12 14:38
Оценка:
Коллеги, приветствую!
Есть табличка заказов Deal (MSSQL Server 2008 R2):
Id, ... , ...
Есть связаная с ней табличка DealTrace:
Id, DealId, Status, ...

У объекта Deal на протяжении жизни статус меняется много раз, каждый раз дописывая в DealTrace новую строку (необходимо хранить историю статусов).

Проблема возникает при работе со статистикой, а именно получение большого кол-ва Deal'ов и выяснение их текущих статусов.
Выполняется запрос вида:
SELECT * FROM Deal d
INNER JOIN DealTrace dt on d.Id = dt.DealId AND dt.id = (SELECT MAX(id) FROM DealTrace WHERE dealid=d.id )

В нашей системе с сотнями и сотнями INSERT'ов и SELECT'ов в секунду на больших объёмах этот запроc нещадно тормозит.
Индексы построены. Подумываем переводить часть объектов из базы на noSQL чтобы разгрузить сиквел, однако, пока нет чёткой понимания что переводить (и на какой рост объемов при этом можно будет расчитывать).

Я вижу несколько путей решения со своими недостатками:
— писать статусы в DealTrace, а тек-ий статус хранить в Deal обновляя его UPDATE'ом (кажется, самое неудобное решение — UPDATE убъет всю производительность lock'ами, или нет?)
— перенести Deal целиком в noSQL базу, целиком брать объект и обновлять в нем список статусов (избавляемся от сложных запросов в процессе жизнидеятельности Deal'а и запроса списка Deal'ов, но возникает потребность в доп. данных для запросов по Deal'ам с определённым статусом)
— что то еще?
sql parent child status highload
Re: Хранение статуса платежа в высоконагруженной базе
От: igor_ku  
Дата: 28.03.12 14:55
Оценка:
Здравствуйте, PetrovichForever, Вы писали:

PF>- что то еще?


В очень похожей ситуации я делал денормализацию. Т.е. делал отдельную таблицу для хранения только последнего (текущего) статуса. Добавляется некоторый саппорт этой таблицы, наример триггер(ы). Но... Все летало.
Re: Хранение статуса платежа в высоконагруженной базе
От: AmKad  
Дата: 28.03.12 14:58
Оценка:
Посмотри в сторону конструкции
select top 1 with ties ...
...
order by row_number() over(partition by dt.DealId order by dt.id desc) desc
Re: Хранение статуса платежа в высоконагруженной базе
От: dobrik Израиль  
Дата: 28.03.12 15:01
Оценка:
Здравствуйте, PetrovichForever, Вы писали:

PF>Коллеги, приветствую!

PF>Есть табличка заказов Deal (MSSQL Server 2008 R2):
PF>Id, ... , ...
PF>Есть связаная с ней табличка DealTrace:
PF>Id, DealId, Status, ...

PF>У объекта Deal на протяжении жизни статус меняется много раз, каждый раз дописывая в DealTrace новую строку (необходимо хранить историю статусов).


PF>Проблема возникает при работе со статистикой, а именно получение большого кол-ва Deal'ов и выяснение их текущих статусов.

PF>Выполняется запрос вида:
PF>SELECT * FROM Deal d
PF>INNER JOIN DealTrace dt on d.Id = dt.DealId AND dt.id = (SELECT MAX(id) FROM DealTrace WHERE dealid=d.id )

PF>В нашей системе с сотнями и сотнями INSERT'ов и SELECT'ов в секунду на больших объёмах этот запроc нещадно тормозит.

PF>Индексы построены. Подумываем переводить часть объектов из базы на noSQL чтобы разгрузить сиквел, однако, пока нет чёткой понимания что переводить (и на какой рост объемов при этом можно будет расчитывать).

PF>Я вижу несколько путей решения со своими недостатками:

PF>- писать статусы в DealTrace, а тек-ий статус хранить в Deal обновляя его UPDATE'ом (кажется, самое неудобное решение — UPDATE убъет всю производительность lock'ами, или нет?)
PF>- перенести Deal целиком в noSQL базу, целиком брать объект и обновлять в нем список статусов (избавляемся от сложных запросов в процессе жизнидеятельности Deal'а и запроса списка Deal'ов, но возникает потребность в доп. данных для запросов по Deal'ам с определённым статусом)
PF>- что то еще?

попробуйте так:

SELECT * FROM Deal d
INNER JOIN
(select status, dealid, row_number() over (partition by dealid order by id desc) r from DealTrace) dt
on d.Id = dt.DealId AND dt.r=1
dobrik
Re[2]: Хранение статуса платежа в высоконагруженной базе
От: dobrik Израиль  
Дата: 28.03.12 15:19
Оценка:
Здравствуйте, dobrik, Вы писали:

D>Здравствуйте, PetrovichForever, Вы писали:


PF>>Коллеги, приветствую!

PF>>Есть табличка заказов Deal (MSSQL Server 2008 R2):
PF>>Id, ... , ...
PF>>Есть связаная с ней табличка DealTrace:
PF>>Id, DealId, Status, ...

PF>>У объекта Deal на протяжении жизни статус меняется много раз, каждый раз дописывая в DealTrace новую строку (необходимо хранить историю статусов).


PF>>Проблема возникает при работе со статистикой, а именно получение большого кол-ва Deal'ов и выяснение их текущих статусов.

PF>>Выполняется запрос вида:
PF>>SELECT * FROM Deal d
PF>>INNER JOIN DealTrace dt on d.Id = dt.DealId AND dt.id = (SELECT MAX(id) FROM DealTrace WHERE dealid=d.id )

PF>>В нашей системе с сотнями и сотнями INSERT'ов и SELECT'ов в секунду на больших объёмах этот запроc нещадно тормозит.

PF>>Индексы построены. Подумываем переводить часть объектов из базы на noSQL чтобы разгрузить сиквел, однако, пока нет чёткой понимания что переводить (и на какой рост объемов при этом можно будет расчитывать).

PF>>Я вижу несколько путей решения со своими недостатками:

PF>>- писать статусы в DealTrace, а тек-ий статус хранить в Deal обновляя его UPDATE'ом (кажется, самое неудобное решение — UPDATE убъет всю производительность lock'ами, или нет?)
PF>>- перенести Deal целиком в noSQL базу, целиком брать объект и обновлять в нем список статусов (избавляемся от сложных запросов в процессе жизнидеятельности Deal'а и запроса списка Deal'ов, но возникает потребность в доп. данных для запросов по Deal'ам с определённым статусом)
PF>>- что то еще?

D>попробуйте так:


D>SELECT * FROM Deal d

D>INNER JOIN
D>(select status, dealid, row_number() over (partition by dealid order by id desc) r from DealTrace) dt
D>on d.Id = dt.DealId AND dt.r=1

и добавить WITH(NOLOCK) к deal можно
dobrik
Re: Хранение статуса платежа в высоконагруженной базе
От: Дельгядо Филипп Россия  
Дата: 28.03.12 21:23
Оценка:
Здравствуйте, PetrovichForever, Вы писали:
PF>- что то еще?

Если идет речь о NoSQL, то значит обращение к этим данным идет из ApplicationLayer.
Тогда можно сделать следующее:
1. Сделать табличку с текущим состоянием Deal.
Если ее формирование через триггеры устраивает по производительности — то не парится.
Если нет, то
2. Хранить на AppLayer текущее состояние.
3. При запросе текущего состояния — если он есть в кэше — отдавать оттуда.
Если нет в кэше — то взять последний из БД и обновить табличку Deal
4. Раз в сколько-то update (зависит от скорости изменения и нагрузки) записывать актуальный в deal

Это позволяет, в зависимости от условий, в несколько раз (иногда — десятков) уменьшить число update и блокировок.
Если проект позволяет этим обойтись — то и ладно.

Но при указанной нагрузке особых проблем быть не должно...
Re: Хранение статуса платежа в высоконагруженной базе
От: Аноним  
Дата: 29.03.12 04:33
Оценка:
Здравствуйте, PetrovichForever, Вы писали:

PF>- писать статусы в DealTrace, а тек-ий статус хранить в Deal обновляя его UPDATE'ом (кажется, самое неудобное решение — UPDATE убъет всю производительность lock'ами, или нет?)


Нет, это rowlock, он ничего убьет, разве что вы дрочите постоянно одни и те же записи.

PF>- перенести Deal целиком в noSQL базу, целиком брать объект и обновлять в нем список статусов (избавляемся от сложных запросов в процессе жизнидеятельности Deal'а и запроса списка Deal'ов, но возникает потребность в доп. данных для запросов по Deal'ам с определённым статусом)


Нет смысла, разве что key-value в качестве кэша, но вы запаритесь с таким подходом держать его консистентным.

PF>- что то еще?


Да.
— Шардинг по номеру клиента или чему-то подобному чтобы распределить нагрузку на несколько нод.
— Архивирование ненужных данных в read-only хранилище. Уверен что срок жизни ордера меньше месяца.
— Денормализация. Сокращайте запросы к DealTrace и сохраняйте предвычичлимые поля в Deal.
— Сокращайте количество запросов.

У нормального разработчика такая задача вообще не должна вызывать проблем.
Re[2]: Хранение статуса платежа в высоконагруженной базе
От: AmKad  
Дата: 29.03.12 06:37
Оценка:
Здравствуйте, AmKad, Вы писали:

AK>Посмотри в сторону конструкции

AK>
AK>select top 1 with ties ...
AK>...
AK>order by row_number() over(partition by dt.DealId order by dt.id desc) desc asc
AK>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.