Foxpro SQL 

Работаем в Foxpro c базой SQL Server

Visual Foxpro - многофункциональный инструмент для работы с базами данных. У него так же есть средства для работы с другими базами данных используя технологию "клиент-сервер", и в современных реалиях для многих разработчиков и заказчиков стала заманчивой перспектива разместить данные в базе SQL-Server, Oracle, MySQL или другой базе SQL.Так как Microsoft естественно ненавязчиво продвигает к использованию свой SQL Server путем создания некоторых средств исключительно для работы из VFP именно с этим продуктом, то не будем (пока еще) пытаться свернуть с рельс и уделим внимание их стремлению.

Долгие годы в народе звучат рассуждения и сетования на политику Microsoft по которой в жертву стратегическим планами этой компании приносятся целые (не всегда плохие) продукты. Очевиден тот факт, что FoxPro фактически стал "костью в глотке" уже не только победе SQL Server в масштабе всей планеты, но и (что гораздо ужаснее) и NET-технологиям. Как бы не потела Microsoft над ADO.NET, но при достаточно поверхностном сравнении очевидно, что чтобы создать в VS.NET функционал подобный VFP им понадобится наверное лет сто.


Тем не менее постараемся не предвзято обойтись с обсуждением разных продуктов и попытаться выявить наиболее оптимальные их сочетания в разных условиях.

Итак. Нужен ли Фокспро SQL Server? Если да, то в каких ситуациях?

1. Когда бы не советовал переходить на SQL:
Размеры Ваших таблиц не превышают гигабайта. Заявленная производительность локальной сети 100Mb/s, реальная - >= 50.

В данном случае Вам предлагается оценить еще некоторые ресурсы и спланировать затраты. Во первых оцените типовой размер физической памяти на ваших компьютерах и постарайтесь проанализировать требования к памяти на типовых запросах ваших программ к данным. Достаточно зафиксировать факты полного использования физической памяти в процессе запросов. Для этого можно воспользоваться диспетчером задач Windows. Другим путем - если имеют место долговременного выполнения запросов - попробуйте устранить эти зависания путем временного добавления физической памяти на компьютер. Дело в том , что для FoxPro остается критическим наличие памяти для оптимизации. Разница в скорости выполнения запросов - несколько порядков. Другими словами - стоит в процессе запроса использовать всю память - отрубается оптимизация и вы получаете приложение - тормоз. Полезно также проанализировать варианты оптимизации запросов из программы используя средства Sys(3054) и Sys(3092). А смысл всего сказанного выше в том, что при доступе к данным на одном компьютере или в достаточно производительной сети VFP будет быстрее, чем SQL. Причина - более простые технологии распределения памяти, кэширования и доступа к данным, а так же - отсутствие затрат на ODBC. Если камнем преткновения является производительность сети, то попробуйте ввести принудительную буферизацию с помощью локальных курсоров где это можно. Так, например, если у вас справочник клиентов содержит сотню тысяч наименований и вы ссылаетесь на него из GRID (или BROWSE) листая таблицу заголовков документов, то есть смысл предварительно создать локальный курсор с индексами на ключи и искать сначала значения в нем, а потом обращаться к источнику. Все результаты обращений к источнику сбрасывайте в локальный курсор. Постарайтесь везде использовать только SET RELATION , а не LOCATE или SEEK. Естественно я не говорю о соблюдении всех правил, необходимых для работы оптимизации RushMore. Имеется железная практика, когда в результате анализа жалоб на медленность FoxPro выясняется, что разработчик не знает и не соблюдает условий для работы оптимизации RushMore и в результате - порочит добрейшее имя этого продукта.

Наличие нескольких удаленных точек (например с доступом по телефонной линии) при основной работе в локальной сети так же не является необходимым условием перехода на SQL. Лучше написать отдельные приложения для этих точек с использованием примитивного Automation-server на FoxPro, чем переводить все, что есть на SQL.

2. Когда вы не обойдетесь без SQL Server или Oracle

Некоторые из Ваших таблиц превышают (или могут в перспективе превысить) размер 2Gb. Уверен. Ограничение на размер файлов в VFP - умышленно не ликвидируется. Хотя с другой стороны при приближении к этим критическим размерам и при наличии приличного числа одновременных сессий FoxPro начинает несомненно уступать SQL Server по производительности в целом. Тут уже без более сложных серверных технологий не обойтись. Ограничение в 2Gb мешает FoxPro в другом случае, который будет упомянут ниже.

Если сеть все таки тормозит или основная работа ведется с удаленных рабочих мест, то вам, как не крути, придется переходить на технологию Клиент-Сервер. В этом случае однозначно посоветую не тратить время зря и реализовывать эту технологию с размещением данных в SQL Server или Oracle (забыть про automation и DBF). Как показывает практика - только доступ к COM объектам (Automation серверам) будет уступать в скорости ODBC, не говоря уже о производительности SQL Server на больших объемах данных.

Если Вы создаете тиражируемые продукты, то, естественно, работа с SQL - Server - один из первых критериев, по которому его будут оценивать.

Есть показатель по которому SQL Server предпочтительнее DBF - надежность. Индексы практически не рушатся.

3. Когда FoxPro и SQL Server нужен ТРЕТИЙ - ADO.NET

Весьма редкая ситуация, но имела место.
Во первых. Самые распространенные отзывы, которые приходилось слышать от клиентов, которые начинают работать с SQL сервером после FoxPro : "too stupid database" или "SQL Server - it is just SELECT, INSERT, UPDATE, DELETE" . Возникали эти возгласы, как правило, в процессе попыток написать хранимые процедуры на T-SQL или PL-SQL(Oracle). Проблема имеет место и очень актуальна! Написать более-менее сложную процедуру на T-SQL, которая заменяла бы программу на FoxPro, - затея абсолютно не оправданная. Полностью согласен: T-SQL и PL-SQL - издевательство над разработчиком. Заявляю это не без оснований. Практически реализовать сложный функционал - возможно, но работать это будет ужасно и отрицательных эмоций Вы поимеете очень много. Так что советую - не тратьте время зря. Не теряя времени создавайте COM (automation) сервер на VFP, размещайте его на сервере с SQL и пишите процедуры, которые будут выбирать исходные данные из SQL Server, обрабатывать их реализуя сложный функционал на основе отработанных ранее кодов на FoxPro и отсылайте результат непосредственно клиенту. Запись результата во временные базы SQL при условии, что нет возможности отключить транзакции, опять убьет ваше приложение. Отработка сложных (да и любых) алгоритмов в FoxPro тем более оправдана, что даже внутри SQL на T-SQL для доступа и модификации данных вам придется выбирать их во внутренние курсоры. Уж лучше выбрать их в курсоры FoxPro. В способностях FoxPro как удаленного сервера в технологии "Клиент-Сервер" сомневаться не приходится. Видел кучу сайтов, которые реализованы именно на FoxPro. При этом FoxPro замещает не только SQL Server при доступе к данным, но и целиком ASP, работая как генератор HTML страниц.

Вот тут то и вредит умышленно не ликвидируемое ограничение на размер файла в FoxPro. Реальный пример: Приложение реализует схему "центральная база" и "оторванные представления" по районам региона и занимается учетом расчета с населением за газ. ~400000 абонентов. Ежемесячно печатают грузовик квитанций. Сквозной учет. Т.е. нет обязательных ежемесячных режимов превращающих документы прошлых месяцев в свернутое сальдо. Продолжительность периода - любая. Размер баз за год вырастает под 70Gb. Одна из процедур работая при формировании отчетов по расчетам позволяет динамически выстроить в один список счета к оплате и документы оплаты в порядке хронологии, перекрыть их по абонентам, вывести сальдо и реализацию. Размер 2Gb будет превышен при попытке выбрать в такой курсор документы более чем за три месяца. Естественно принято решение (и в целях ускорения процедуры) создавать на прошлый месяц промежуточное сальдо, которое, если программа видит, принимается за входящее и более ранние документы не выбираются в курсор. Все прекрасно, пока не возникает бредовой идеи получить расчеты целиком за год. Естественно ни кто не хочет это суммировать вручную и возникает дилемма:

  • написать функционал, который будет получать итоговые данные по месяцам и складывать их в кучу;

  • попробовать вместо FoxPro automation server - ADO.NET

Фактически работая как automation server рядом с SQL Server FoxPro замещает именно прямое назначение ADO.NET . Думаю что это решение будет более правильным. 

Если выбираем SQL Server и не хотим переписывать приложение "с нуля".  

Итак, вы все таки решили связать будущее с SQL Server. Хорошим шагом было бы поискать наработанные решения, которые позволили бы реализовать нужный функционал в FoxPro приложении. Смотрим и видим: Большинство из предлагаемых средств разработки ориентированы на то, что вы намерены переписать приложение с нуля. Mere Mortals Framework, CodeMine Framework, ... - хорошие штуки, но изначально вам будут предложены базовые средства, которые Вы должны взять за основу своего приложения. А что же делать, если эта основа уже давно взята? Можно ли путем "хирургического вмешательства" адаптировать FoxPro приложение для работы с данными в базах SQL Server ? 

Практика показывает, что можно. При этом изначально нужно понимать следующие вещи:
Практически никогда речь не может идти о разовом переходе с DBF на SQL при котором приложение теряет функции работы с данными в DBF и приобретает способность работы с данными в базах SQL. Если даже в перспективе вы планируете полностью отказаться от DBF, то процесс переноса данных будет затянут и переход обычно осуществляется с несколько попыток и в несколько этапов. Конечно, в процессе перехода можно параллельно развивать два приложения: исходное, которое пока еще работает с DBF, и его копию, на которой уже началась операция по адаптации к работе с SQL. Но оправдано ли параллельное развитие двух приложений? Считаю, что более целесообразно попробовать наделить одно и то же приложение новыми функциями не влияя на существующие.
Большинство сред разработки (frameworks) фактически предлагают именно такое решение. Среда разработки, в которой выполнено приводимое выше в пример приложение по расчетам с населением за газ (как и базовая система учета к которой оно относится) фактически вводит уровень абстрагирования предметной области приложения от типов источников данных (DBF, SQL Server, Oracle, ...) и от механизма доступа к ним (прямой доступ к DBF, ODBC, Automation, ADO, ...). Иными словами приложение работает с набором объектов и функций практически не зная о типах данных и транспортных протоколах. Одно и то же приложение работает с центральной базой SQL Server в центральном офисе газовой компании и с DBF (в качестве оторванного представления) в районах, которые (DBF) содержат данные только текущего района (участка). 

Начнем с того, что в целом проблемы, возникающие в процессе адаптации FoxPro приложения к работе с SQL Server, можно разделить на две группы: 

  • Практически один процент запросов, которые составляют самые простые, на FoxPro может удовлетворять стандарту SQL и не будет порождать ошибок при передаче исходного текста запроса в функцию SQLExec(). Если при этом добавить различие в наборе и синтаксисе функций, которые любит использовать разработчик в запросах, то получится, что мы имеем два разных языка, синтаксис одного из которых нужно преобразовывать к синтаксису другого.

  • Приложение на FoxPro во многих случаях использует прямой доступ к данным (LOCATE, SEEK, GO, BROWSE, ...), что не совместимо с технологией Клиент-Сервер. Цель - научить приложение вести себя по разному в случае возможности прямого доступа к данным и в случае ее отсутствия (клиент-сервер) и при этом изменить минимум кода. 

 Преобразование синтаксиса SQL запросов. 

Во первых. Синтаксис запросов в FoxPro несравнимо более свободный, чем допускает стандарт SQL. Так большинство кодов написанных на версия VFP до седьмой будут содержать сокращенные ключевые поля, например, SELE ... FROM ... WHER ... . Порядок фраз в FoxPro также может быть любой, но он является строго определенным для SQL. Есть еще куча различий, которые будут конкретно описаны ниже. Во вторых - использование функций в запросах - обычное дело. Хотя для множества функций и можно найти эквивалент в T-SQL, но имена и синтаксис будет различен. В третьих - не все манипуляции с переменными FoxPro в запросах можно реализовать путем передачи их значений в ODBC префиксом "?". Возникают проблемы, когда выбираются данные во временную таблицу в базе TEMPDB. 

Прежде чем начать описание предлагаемых средств для преобразования синтаксиса определим, что практически разработчики используют два метода адаптации запросов: конвертация синтаксиса на этапе выполнения программы и на этапе разработки. В обоих случаях можно использовать функции библиотеки EFoxSQL.FLL

Основные функции библиотеки EFoxSQL.FLL для преобразования синтаксиса FoxPro к T-SQL:

  • E_SQL_SELECT_CONVERT()    - непосредственно преобразование синтаксиса;

  • E_SQL_FIND_VARIABLES()         - преобразование ссылок на переменные и выражения FoxPro в их значенияж

  • E_SQL_REMOVE_DIRECTIVES()    - убирает префиксы-дериктивы из запроса для выполнения его в FoxPro

  • E_SQL_CREATE_STRU_CONVERT()     - преобразует названия типов и добавляет ключевые слова в команду CREATE

Библиотека подключается стандартным способом SEL LIBRARY TO ... EFOXSQL.FLL ADDITIVE

Синтаксис:

Запрос с синтаксисом T-SQL = E_SQL_SELECT_CONVERT(Запрос с синтаксисом FoxPro)

Функция выполняет следующие действия по преобразованию текста запроса Select SQL

Изначально FoxPro позволял использовать усеченные минимум до четырех знаков любые ключевые слова и названия функций. В версиях VFP начиная с 7-й по умолчанию включена проверка синтаксиса, которая старается дополнить фразы до полной длины в процессе их написания, но возможность писать сокращенные фразы все же остается. А многие запросы были написаны еще на более ранних версиях. Так что функция E_SQL_SELECT_CONVERT постарается дополнить ключивые слова и если, например, ваше выражение напоминало

    SELE DIST ... FROM ... GROU BY ...

то в результате функции оно будет выглядеть

    SELECT DISTINCT ... FROM ... GROUP BY ...

Например, при выполнении такого запроса

SELECT company, country FROM Customer GROUP BY country

В версии FoxPro начиная с 8 и выше, получаем сообщение об ошибке типа

SQL: GROUP BY clause is invalid (Error 1807)

Причем в младших версиях FoxPro подобный запрос работал без проблем.

Причина:
Начиная с версии Visual FoxPro 7.0, были ужесточены требования к корректности конструкции SQL-запросов. 
В данном случае запрос содержит неоднозначность: Какое именно значение поля company надо взять из таблицы, если для одного и того же значения country их может существовать несколько?

В младших версиях FoxPro в этом случае использовалось первое попавшееся значение. В старших версиях FoxPro такая конструкция воспринимается как синтаксически некорректная.

Решение:
Следует перечислить в конструкции GROUP BY все поля результирующей выборки, которые не имеют агрегирующих функций

SELECT company, country FROM Customer GROUP BY company, country

или добавить любую агрегирующую функцию к тем полям, которые не перечислены в конструкции GROUP BY

SELECT MAX(company) as company, country FROM Customer GROUP BY country

Впрочем, если Вы переводите свое приложение со старой версии FoxPro в новую версию, то можно явно указать FoxPro, что нужно использовать старые правила разбора и выполнения SQL-запроса при помощи настройки

SET ENGINEBEHAVIOR 70

Однако, по возможности, все-таки лучше придерживаться стандартных правил составления запросов в том смысле, что в конструкции GROUP BY должны быть перечислены все поля, которые не участвуют в агрегирующих функциях.