Обсуждение статьи "SQL и MQL5: Работаем с базой данных SQLite"

 

Опубликована статья SQL и MQL5: Работаем с базой данных SQLite:

Данная статья рассчитана на программистов, проявившим интерес к использованию SQL в своих проектах. В статье читателям представляется функциональность SQLite, а также рассматриваются ее преимущества. Статья не требует знание функций SQLite, но минимальные знания SQL приветствуются.

SQL и MQL5: Работаем с базой данных SQLite

Многие разработчики задумывались над необходимостью использовать в своих проектах базы данных для хранения информации, но каждый раз останавливались, зная, какими дополнительными затратами времени сопровождается установка SQL-сервера. Если для программистов выполнить это не так сложно (или СУБД уже установлена для других целей), то для обычного пользователя данная операция вызовет много вопросов, либо вообще отобьет желание устанавливать софт.

В таком случае программист просто не связывается с СУБД, понимая, что кроме него этим решением воспользуются единицы. В конечном итоге в ход идет работа с файлами (часто не одним при разрозненности данных): использование CSV, реже XML или JSON, либо запись бинарных данных с жестким размером структуры и т.п.

Но, как оказывается, есть отличная альтернатива SQL-серверу! При этом не нужно устанавливать дополнительный софт, вся работа идет локально в вашем проекте, но при этом вы используете всю мощь языка SQL. Имя этой альтернативы - SQLite.

Цель данной статьи - обеспечить быстрый старт в использовании SQLite. Поэтому я не буду углубляться в тонкости и всевозможные наборы параметров или флагов функций, а создам легкую обвертку-коннектор, которая выполняет SQL команды, и на примерах покажу ее применение.

Необходимые условия для работы со статьей:

  • Хорошее настроение ;)
  • Распакуйте архив из приложения к статье в папку рабочего терминала MetaTrader 5
  • Установите любую удобную для вас утилиту просмотра SQLite баз (например, SQLiteStudio)
  • Добавьте в закладки официальную документацию по SQLite http://www.sqlite.org

Автор: o_O

 

Есть пара важных дополнений (и предложений к усовершенствованию:))

1. Автор пользует функцию sqlite_open(), но есть еще и более гибкая функция sqlite_open_v2(), которая умеет работать с флагами открытия, а значит: - управлять разграничением доступа к файлу БД; - создавать временные in-memory базы; - работать с БД по URI, а не только в локальной файловой системе и т.д.

#define SQLITE_OPEN_READONLY         0x00000001  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_READWRITE        0x00000002  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_CREATE           0x00000004  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_DELETEONCLOSE    0x00000008  /* VFS only */
#define SQLITE_OPEN_EXCLUSIVE        0x00000010  /* VFS only */
#define SQLITE_OPEN_AUTOPROXY        0x00000020  /* VFS only */
#define SQLITE_OPEN_URI              0x00000040  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_MEMORY           0x00000080  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_MAIN_DB          0x00000100  /* VFS only */
#define SQLITE_OPEN_TEMP_DB          0x00000200  /* VFS only */
#define SQLITE_OPEN_TRANSIENT_DB     0x00000400  /* VFS only */
#define SQLITE_OPEN_MAIN_JOURNAL     0x00000800  /* VFS only */
#define SQLITE_OPEN_TEMP_JOURNAL     0x00001000  /* VFS only */
#define SQLITE_OPEN_SUBJOURNAL       0x00002000  /* VFS only */
#define SQLITE_OPEN_MASTER_JOURNAL   0x00004000  /* VFS only */
#define SQLITE_OPEN_NOMUTEX          0x00008000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_FULLMUTEX        0x00010000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE      0x00020000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE     0x00040000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL              0x00080000  /* VFS only */

2. Я пользовался(юсь) sqlite для решения задачи ускорения оптимизации советника в тех случаях, когда он использует "тяжелый" в расчетах индикатор. Логичным решением в такой ситуации выглядит сохранение показаний индикатора за период оптимизации в базе данных при первом прогоне, а при последующих - непосредственная добыча уже рассчитанных показаний из БД. Так вот, если пользоваться движком sqlite в "дефолтном виде", процесс посылки множества INSERT и SELECT запросов начинает занимать ооочень много времени. Практическим путем было установлено, что выход состоит в использовании либо 1) in-memory базы данных, что не всегда хорошо, если мы хотим оставить данные на потом и 2) #pragma-директив движка SQL.

Второй вариант боле предпочтителен, так как избавляет от необходимости дампа базы данных из RAM на диск. Делается это так: обязательно перед созданием первой таблицы в базе данных необходимо отправить ей следующие запросы:

"PRAGMA temp_store = MEMORY;"
"PRAGMA page_size = 65536;"
"PRAGMA cache_size = 16384;"
"PRAGMA journal_mode = OFF;"
"PRAGMA locking_mode = EXCLUSIVE;"
"PRAGMA synchronous = OFF;"

Ну, а после этого уже можно

"CREATE TABLE IF NOT EXISTS"

и т.д.

Всем удачи!

 
alsu:

Есть пара важных дополнений (и предложений к усовершенствованию:))

1. Автор пользует функцию sqlite_open(), но есть еще и более гибкая функция sqlite_open_v2(), которая умеет работать с флагами открытия, а значит: - управлять разграничением доступа к файлу БД; - создавать временные in-memory базы; - работать с БД по URI, а не только в локальной файловой системе и т.д.

2. Я пользовался(юсь) sqlite для решения задачи ускорения оптимизации советника в тех случаях, когда он использует "тяжелый" в расчетах индикатор. Логичным решением в такой ситуации выглядит сохранение показаний индикатора за период оптимизации в базе данных при первом прогоне, а при последующих - непосредственная добыча уже рассчитанных показаний из БД. Так вот, если пользоваться движком sqlite в "дефолтном виде", процесс посылки множества INSERT и SELECT запросов начинает занимать ооочень много времени. Практическим путем было установлено, что выход состоит в использовании либо 1) in-memory базы данных, что не всегда хорошо, если мы хотим оставить данные на потом и 2) #pragma-директив движка SQL.

Второй вариант боле предпочтителен, так как избавляет от необходимости дампа базы данных из RAM на диск. Делается это так: обязательно перед созданием первой таблицы в базе данных необходимо отправить ей следующие запросы:

Ну, а после этого уже можно

и т.д.

Всем удачи!

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

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

Поэтому нужно отдавать себе отчет, что эффективность использования реляционных, многосвязных моделей данных, в первую очередь зависит от решаемых задачь, а в указанных примерах ИМХО, это м.б. разве что "притянуто за уши".
 

 
Есть колончатая SQL СУБД называется MonetDB. Это бесплатна СУБД, предназначенная для хранения данных в столбцах, у этой базы неплохая скорость и надежность работы. Если я не ошибаюсь к МТ представленным в топике образом можно подключить любую СУБД стандарта SQL.
 
revers45:

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

 

Читай еще раз, хоть это избыточно и не рационально: для оптимизации советника


 

Возможность использования есть и это хорошо. Другое дело что SQLite не стоит использовать для серьезных проектов. Во всяком случае я бы не рекомендовал. Сам сталкивался не раз с проблемой коллизий на ней. Скажем, если торговый робот прикреплен к различным чартам, а использует одну базу, причем обращение происходит к одной таблице общего назначения (скажем регистрация/изменение сессий, аккаунтов), то в любом случае вы получите ошибку типа "таблица заблокирована". И не важно что транзакции все завершены, курсоры все закрыты и БД открыта была в shared режиме. Эта проблема известна и разработчикам SQLite.

Как по мне, так из файловых БД с поддержкой SQL лучше MS Access. Как ни ругайте мелкомягких, но я от SQLite ушел на MS Access и вовсе не жалею. OleDB драйвер Jet 4.0 ставится даже с Win98, так что проекты работают на всех OC Windows.

 

Скрипт не рабочий, из "коробки" не работает, на помойку такие проекты.

В консоли выдает  https://s.mail.ru/9dWTNLqx6RT2/img-2015-11-10-20-15-44.png

В таблице https://s.mail.ru/QZyK6HwhMvo9/img-2015-11-10-20-16-18.png

Код https://s.mail.ru/2ooLdMg5MrHP/img-2015-11-10-20-16-56.png 

 
delphiec:

Скрипт не рабочий, из "коробки" не работает

курите мануал, если не понимаете что и как делать

 

В связи с изменениями в копировании struct - поправлен файл ByteImg.mqh на использование union

новый FastFile скачайте в его публикации https://www.mql5.com/ru/forum/6291#comment_4967832
Файлы:
ByteImg.mqh  6 kb
 
 string query="SELECT COUNT(*) FROM '"+table+"' WHERE low<"+lowLevel+" AND high>"+highLevel+" AND date>'"+TimeToString(time)+"'";

if(sql3.Query(tbl,query)!=SQLITE_DONE)

        {

         Print(sql3.ErrorMsg());

         return 0.0;

        }

      sql3.Disconnect();

      CSQLite3Cell cell;

      tbl.Cell(0,0,cell);

      int gg=cell.GetInt64();


gg всегда выдает 0. Хотя если кверю ввести на прямую в БД, то выдает правильное значение.

И если вместо COUNT поставить какую-нибудь колонку и потом посмотреть размер массива ArraySize(tbl.m_data), то все гуд. Т.е. count не работает. Не знаю, может я что-то не так делаю...

 
лучше всегод продебажить кверю
Причина обращения: