среда, 19 сентября 2018 г.

Подсчет количества значений массива json в строке записи MS SQL

Появилась потребность сохранять в БД последовательность событий, происходящих на сайте одного из проектов. В виду того, что события могут происходить сильно разные, параметры этих событий записываются как одно JSON поле. С разной структурой. Данных много, приходят по нескольку десятков событий каждую секунду.

 SELECT TOP (10) [Id]
 ,[EventStart]
 ,[EventEnd]
 ,DATEDIFF(ms, eventstart, eventend) ms
 ,[DataJson]
 ,[RequestType]
FROM [Audit]
where RoutePath = 'Object/getInfos' and DATEADD(minute, -1, GETDATE()) < EventStart
order by id desc

Результат:

Id         EventStart                  EventEnd                    ms   DataJson                                               RequestType
---------- --------------------------- --------------------------- ---- ------------------------------------------------------ -------------------------
69095982   2018-09-19 13:06:29.2800000 2018-09-19 13:06:29.2966667 16   {"EventType":"Object/getInfos","Environment":{"UserNam POST
69095981   2018-09-19 13:06:29.2800000 2018-09-19 13:06:29.2966667 16   {"EventType":"Object/getInfos","Environment":{"UserNam POST
69095980   2018-09-19 13:06:29.2333333 2018-09-19 13:06:29.2800000 47   {"EventType":"Object/getInfos","Environment":{"UserNam POST
69095979   2018-09-19 13:06:29.0766667 2018-09-19 13:06:29.0933333 17   {"EventType":"Object/getInfos","Environment":{"UserNam POST
69095978   2018-09-19 13:06:29.0633333 2018-09-19 13:06:29.0766667 13   {"EventType":"Object/getInfos","Environment":{"UserNam POST
69095976   2018-09-19 13:06:28.8266667 2018-09-19 13:06:28.8733333 47   {"EventType":"Object/getInfos","Environment":{"UserNam POST
69095975   2018-09-19 13:06:28.4833333 2018-09-19 13:06:28.8133333 330  {"EventType":"Object/getInfos","Environment":{"UserNam POST
69095974   2018-09-19 13:06:28.6400000 2018-09-19 13:06:28.6566667 16   {"EventType":"Object/getInfos","Environment":{"UserNam POST
69095973   2018-09-19 13:06:28.5000000 2018-09-19 13:06:28.5766667 76   {"EventType":"Object/getInfos","Environment":{"UserNam POST
69095970   2018-09-19 13:06:28.1733333 2018-09-19 13:06:28.1866667 13   {"EventType":"Object/getInfos","Environment":{"UserNam POST

(10 rows affected)

Дошло дело до аналитики, и потребовалось создать выборку, где необходимо было подсчитать для каждой строки во вложенном поле JSON количество элементов массива. Stackoverflow забит записями о том, как выбрать из единичного поле но сложной структуры, но при этом нет примеров, о том, как посчитать для многих строк.

Первой итерацией стало получение из единичной строки, как указано здесь

declare @s varchar(8000)
set @s = '{ "EventType": "Object/getInfos", "Environment": { "MachineName": "MASTER", "DomainName": "IIS APPPOOL", "CallingMethodName": "Web2.Controllers.ObjectController.GetInfos()", "AssemblyName": "Web2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Culture": "ru-RU" }, "StartDate": "2018-09-18T15:06:23.7361083+03:00", "EndDate": "2018-09-18T15:06:24.0485875+03:00", "Duration": 312, "Action": { "HttpMethod": "POST", "ControllerName": "Object", "ActionName": "getInfos", "ActionParameters": { "ids": [320, 292, 299, 289, 8022], "force": false }, "UserName": "a.user", "RequestUrl": "/object/getInfos", "ResponseStatus": "200 OK", "ResponseStatusCode": 200 } }'
select *
from Openjson(@s, '$.Action.ActionParameters.ids') oj


Результат:

key        value    type
---------- -------- ----
0          320      2
1          292      2
2          299      2
3          289      2
4          8022     2
(5 rows affected)

Т.е. достаточно было совместить основной запроc с OpenJson. Однако, при выполнении Cross Apply запрос пытался получить данные о длинах массивов по большому числу строк и уходил в длительную обработку.

Добавил подзапросом сперва получение последних по времени 10 строк, а по ним уже выполнил CROSS APPLY с группировкой

select 
 c1.id
 ,c1.ms
 ,count(x.value) cnt
from(
   SELECT TOP (10) [Id]
    ,[EventStart]
    ,[EventEnd]
    ,DATEDIFF(ms, eventstart, eventend) ms
    ,[DataJson]
   FROM [Audit]
   where RoutePath = 'Object/getInfos' and DATEADD(minute, -1, GETDATE()) < EventStart
   order by id desc
   ) c1
CROSS APPLY OPENJSON(JSON_QUERY(c1.DataJson, '$.Action.ActionParameters.ids')) AS x
group by c1.id, c1.ms
order by count(x.value) desc

Результат:

id                   ms          cnt
-------------------- ----------- -----------
69110646             63          87
69110659             60          72
69110653             360         45
69110644             17          22
69110651             17          13
69110650             13          9
69110658             16          7
69110652             17          7
69110655             326         6
69110645             296         1

(10 rows affected)

Надеюсь, кому-нибудь поможет :)

понедельник, 24 августа 2015 г.

Sharepoint 2013 + Quick Edit


На днях столкнулся с проблемой, когда у одного из пользователей при работе с настраиваемым списком не отображается кнопка быстрого редактирования. При этом создавать и редактировать элементы он может.
По давно сложившейся практике поиск причины такого поведения интерфейса производился методом гугления.
Помимо прочих была найдена вот эта статья по диагностике проблемы, а также проверены все 7 возможных причин возникновения из этой статьи.
Ситуация усложнялась тем, что проблема возникала только у одного пользователя, у остальных проблем с доступом к кнопке Quick edit не возникало. Методом исключения определил, что проблема с профилем пользователя в Sharepoint. Различные браузеры и даже другой ПК давали тот же результат.
Оказывается проблема заключалась в полномочиях. Если у пользователя отсутствуют полномочия на весь список, а разрешения выданы только на какую-либо конкретную папку (как раз так и получилось), то меню быстрого редактирования элементов в списке Sharepoint для этого пользователя будет закрыто.
Удачи в диагностике ваших проблем.

среда, 18 июня 2014 г.

Ошибка в конфигурации Mozilla Firefox 30

После обновления Firefox до 30 версии перестали открываться некоторые внутренние сайты, работающие с ntlm-аутентификацией. Код ошибки: "401 - доступ запрещен. Используются недействительные учетные данные."
Причем в других браузерах проблемы не возникало
Путем проб и ошибок было обнаружено, что проблема возникает только для тех сайтов, которые перечислены в настройке network.automatic-ntlm-auth.trusted-uris.
При этом по ключу ntlm были найдены еще две измененные настройки: network.auth.force-generic-ntlm и network.automatic-ntlm-auth.allow-non-fqdn. Обе эти настройки являются булевыми и были выставлены в true. После восстановления исходных значений сайты стали открываться. Проблема возникла после обновления до 30 версии.
Скрин работающей версии:

вторник, 27 мая 2014 г.

И снова ошибка конфигурации asp.net

В виду того что нарываюсь на ошибку не в первый раз, оставлю для истории. 
MS поменяли настройки по умолчанию для веб-серверов и теперь при публикации приложения на новый сервер, если оно вдруг использует доменную аутентификацию, происходит ошибка конфигурации.
Ошибка HTTP Error 500.19  0x80070021. Происходит она из-за того, что на уровне сервера по умолчанию запрещено переопределять некоторые секции конфиг-файла.
Для того чтобы исправить ситуацию необходимо на сервере открыть файл 
%windir%\system32\inetsrv\config\applicationHost.config
и поменять строчку вида
<section name="windowsAuthentication" overrideModeDefault="Deny" />
на 
<section name="windowsAuthentication" overrideModeDefault="Allow" />.
Аналогичную настройку нужно сделать и для других секций, которые у переопределены в web.config вашего приложения, но имеют настройку overrideModeDefault="Deny" в applicationHost.config.

понедельник, 26 мая 2014 г.

О браузерах

Браузеры поумнели. Может обычному пользователю, не отличающему адресную ссылку и поисковую строку это и наруку, но мне как-то не очень.
Мало того что от меня пытаются спрятать протокол соединения (кому он мешает?), так еще и при вводе в адресную строку норовят увести в поисковый запрос.
Для себя нашел решение: если ищу, добавляю в конце пробел - это всегда классифицируется как поисковый запрос. А уж если ввожу адрес: добавляю в конце "/".

среда, 12 декабря 2012 г.

Архитектура

Есть сущность, которая будет стремиться
Получить автоматизацию в ходе стишка.

На сервере сиквел будет крутиться,
Поддерживающий базу, а в ней уж таблицу,
В которой сущность будет храниться,
Автоматизируемая в ходе стишка.

Класс Entity Framework замаплен в таблицу,
В которой сущность почти что хранится,
Автоматизируемая в ходе стишка.

Возможность была чтоб к таблице пробиться
Сервису SOAP пришлось закрутиться
Который использует класс Entity Framework,
Пишущий данные в тело таблицы,
В которой сущность постоянно хранится,
Автоматизируемая в ходе стишка.

Есть InfoPath-форма, которая, которая злится
Что к сервису придется ей обратиться
Который использует класс Entity Framework,
Пишущий данные в тело таблицы,
В которой сущность возможно хранится,
Автоматизируемая в ходе стишка.

У InfoPath-формы есть код-обработчик
Который использует XPath путь-наводчик
Чтобы записывать данные в поле
Чтобы отправить их сервису что ли?
Чтобы он передал их в класс Entity Framework
Чтобы тот записал их в чудо-таблицу
В которой что-то возможно хранится,
Автоматизируемое в ходе стишка.

И есть разработчик, который стремится
Постичь всю последовательность, что генерится
При разработке автоматизации сущности, что легла в основу стишка.

А так же заказчик, что матерится
При случае не зная к кому обратиться
Когда весь проект под нагрузкой ложится
При эксплуатации автоматизации сущности (по сути ненужности)
Что легла в основу стишка.

среда, 31 октября 2012 г.

Способ сбросить идентификатор элементов в списке Sharepoint

Проблема: после проведения тестирования по добавлению большого количества элементов в список Sharepoint идентификаторы вновь создаваемых элементов имеют неприлично большой размер. Вроде бы ничего страшного, но на кануне большого старта, как-то не по феншую.
Решение: строго говоря, поддерживаемого решения не существует. Все официальные источники рекомендуют пересоздавать список. Однако при большом количестве полей + полей подстановки + рабочих процессов данная рекомендация не подходит.
На просторах интернета было найдено неофициальное решение:
  1. Удалить все элементы из списка
  2. Очистить корзину (вплоть до корзины второго уровня)
  3. На базе с контентом выполнить SQL-скрипт: UPDATE [ContentDB].dbo.AllListsAux set NextAvailableId=1 where ListID='00000000-0000-0000-0000-000000000000', где ContentDB имя Вашей базы с контентом, а 00000000-0000-0000-0000-000000000000 - идентификатор списка.
Решение было опробовано на трех различных списках, проблем не возникло. Однако при применении рекомендую принять все меры предосторожности: потренироваться на тестовом небольшом списке и сделать бекап базы контента.