Задний план
Основное приложение, в котором я работаю, в значительной степени основано на движке базы данных Caché в стиле MUMPS от InterSystems. Все хранится в глобальных массивах. Получение данных из системы для внешней отчетности варьируется от простой боли до вопиюще медленной и болезненной.
Caché предоставляет ODBC-драйвер для базы данных, но если глобальные массивы не имеют ключей в соответствии с критериями выбора, он прибегает к сканированию, и выполнение простого запроса займет несколько часов. Для масштабирования все рабочее пространство имен Caché составляет около 100 ГБ. Я могу писать программы на ObjectScript (диалект MUMPS от Intersystems), которые в этих случаях извлекают данные намного быстрее, чем драйвер ODBC.
Я думаю, что часть проблемы заключается в том, что поставщик приложений не использует поддержку сохраняемости объектов Caché, а вместо этого определяет таблицы SQL как фасад над глобальными массивами, и это часто плохо работает для пакетных запросов.
Я создал базу данных отчетов в MS SQL Server, которая извлекает наиболее распространенные данные (объемом 2,5 ГБ), и даже если ей нужно сканировать каждую таблицу, все результаты возвращаются в течение 3 секунд. К сожалению, обновление данных занимает много времени, поэтому я могу выполнять полное обновление только один раз в неделю и активное обновление один раз в день. Этого достаточно для большинства потребностей, но я хочу сделать лучше.
Я использую Caché 2007, SQL Server 2008 R2, VS2010 в Windows 7 и Windows Server 2008 R2.
Объем вопроса
Мне нужен способ интеграции оперативных данных из исходной базы данных Caché с другими данными на SQL Server. Я хочу иметь возможность интегрировать представления или табличные функции в SQL-запрос и получать данные в реальном времени из исходной базы данных.
Оперативные данные должны быть доступны в SQL Server для обработки. Выполнение этого с дополнительным приложением было бы огромной проблемой и не работало бы с инструментами отчетности, которые просто ожидают отправки запроса через ODBC и получения окончательного набора данных в правильном формате.
Я понимаю, что есть способы получить данные в SQL Server или выполнить те же общие действия, которые я хочу сделать. Этот вопрос не об этом.
Данные должны поступать из программ ObjectScript, запущенных в Caché, поскольку не все данные, которые мне нужны, отображаются через таблицы, определенные SQL, и я получаю контроль, необходимый для обеспечения производительности, пригодной для использования с ObjectScript.
Я ищу совета о любых новых вариантах или о том, как я могу улучшить один из вариантов, которые я пробовал или рассматривал, или о других плюсах или минусах этих подходов.
Что я пробовал до сих пор
Этот проект был упражнением в разочаровании, когда каждый многообещающий путь, который я рассматривал, либо ужасен, либо не работает по какой-то причине. Часто причина в каком-то ненужном ограничении сборок SQLCLR.
Вытягивание всего через драйвер InterSystem Caché ODBC через связанный сервер. SQL Server часто прибегает к сканированию, если он не может отправить условия на удаленный сервер или должен выполнить соединение локально. Сканирование любой нетривиальной таблицы занимает много часов и недопустимо. Кроме того, длина многих столбцов неправильно определяется определениями таблиц SQL в Caché; SQL Server это не нравится и прерывает запрос. См. этот вопрос SO . Я не могу изменить определение таблицы, и поставщик не считает это проблемой, поскольку она работает с MS Access.
Использование OPENQUERY по запросу. Это работает до некоторой степени, но у меня все еще может быть проблема с длиной столбца из предыдущего пункта, и нет способа параметризовать запросы OPENQUERY, поэтому извлекать контекстные данные довольно бесполезно.
Использование SQLCLR для вызова поставщика данных ODBC с помощью табличных функций CLR. Это решает проблемы параметризации и длины данных, хотя и требует от меня определения или изменения функции каждый раз, когда мне нужен новый фрагмент данных. К сожалению, не все интересующие меня элементы данных доступны через SQL. Для некоторых вещей мне нужен прямой доступ к глобальным массивам.
Intersystems предоставляет элемент управления ActiveX, который позволяет запускать программы ObjectScript через TCP на сервере и получать результаты. Это прекрасно работает в автономном приложении C#, но как только я пытаюсь установить соединение из сборки SQLCLR, я получаю нелепую ошибку URI:
Произошла ошибка .NET Framework во время выполнения определяемой пользователем подпрограммы или агрегата «GetActiveAccounts»: System.UriFormatException: Invalid URI: URI пуст. System.UriFormatException: в System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind) в System.Uri..ctor(String uriString) в System.ComponentModel.Design.RuntimeLicenseContext.GetLocalPath(String fileName) в System.ComponentModel. Design.RuntimeLicenseContext.GetSavedLicenseKey(Type type, Assembly resourceAssembly) at System.ComponentModel.LicenseManager.LicenseInteropHelper.GetCurrentContextInfo(Int32& fDesignTime, IntPtr& bstrKey, RuntimeTypeHandle rth) at FacsAccess.GetActiveAccounts.Client.connect() at FacsAccess.GetActiveAccounts ctor() в FacsAccess.GetActiveAccounts.E1.GetEnumerator()
См. этот SO-вопрос без ответа. Есть и другие сообщения. об этом в сети, но никто, кажется, не имеет ни малейшего представления. Это чрезвычайно простая оболочка COM над C++ DLL; он ничего не делает с лицензированием и не имеет причин быть в управляемых библиотеках лицензирования. Интересно, это какой-то шаблон, который пытается получить имя для сборки, у которой нет имени, потому что она была загружена в базу данных SQL.
Intersystems также предоставляет более прямой неуправляемый интерфейс но все эти интерфейсы — C++, которые я не могу использовать через P/Invoke, и я не могу загрузить нечистую сборку смешанного режима C++/CLI в SQLCLR.
Варианты, которые я рассматривал, но кажутся ужасными
Я думал попробовать управление ActiveX через COM-поддержку SQL Server, но это ужасно медленно и очень громоздко.
Я мог бы создать внепроцессную службу для прокси-трафика, но я не могу использовать удаленное взаимодействие .NET из SQLCLR, и вы не должны использовать WCF, и в любом случае это будет очень тяжело для такого простого интерфейса. Я бы скорее свой собственный интерфейс IPC закатал.
Я мог бы написать какую-нибудь дополнительную неуправляемую оболочку с интерфейсом в стиле C для интерфейсов VisM или CacheDirect и получить доступ к ЭТОМУ через P/Invoke.
Не кажется, что это должно быть так сложно, но это действительно доводит меня до отчаяния, и мне нужен взгляд.