기고글 토론 "SQLite: MQL5로 SQL 데이터베이스의 처리" - 페이지 8

 

그리고 질문 #2:

SQLite의 내장 메커니즘을 사용하여 데이터베이스 간에 데이터를 전송하기 위해 ATTACH/DETACH 함수를 사용하려고 하면 트랜잭션 오류 5601...이 발생합니다.

SQLiteStudio에서 동일한 트랜잭션을 실행하면 모든 것이 정상입니다.

일부러 그런 건가요, 아니면 뭔가 잘못된 건가요?

   m_db.Create("IndiTemp","indi",m_db_main.GetStruct(),true);
   string db_path=StringFormat("%s\\Files\\%s.sqlite",
                               TerminalInfoString(TERMINAL_COMMONDATA_PATH),
                               "Indi");
                               
   string query=StringFormat("ATTACH DATABASE '%s' AS X; ",db_path),
          tables[];
          
   int total=m_db.GetTables(tables);
   if(total>0)
     {
      for(int i=0; i<total; i++)
         StringAdd(query,StringFormat("INSERT OR IGNORE INTO %s SELECT * FROM X.%s; ",tables[i],tables[i]));
     }
     
   StringAdd(query,"DETACH X; ");
   m_db.TransactionExecute(query);
 
Daniil Kurmyshev 프로그램 실행 취소)가 발생하며, 아마도 내 라이브러리 코드의 일부인 MQL 함수 내부에서 오류가 발생했을 것입니다:


안타깝게도 DatabaseExport 함수는 테이블 내보내기 기능을받지 못했으며 (이 기능은 원래 의도되었지만) 현재 쿼리 만 지원합니다.

오류 4022에서 테스트 중에 오류가 발생합니까? 그렇다면 테스터는 내보내기 파일 크기에 제한이 있습니다 - 디스크에 기록 된 총 데이터 크기 1GB ?

 
Daniil Kurmyshev SQLite의 내장 메커니즘으로 데이터베이스간에 데이터를 전송하기 위해 ATTACH/DETACH 함수를 사용하려고 하는데 트랜잭션 오류 5601이 발생합니다...

SQLiteStudio에서 동일한 트랜잭션을 실행할 때 모든 것이 정상입니다.

일부러 그런 건가요, 아니면 뭔가 문제가 있는 건가요?

쿼리가 작동하고 경로가 올바른지 확인해야 합니다.
 
Ilyas #:

안타깝게도 데이터베이스 내보내기 함수에는 테이블 내보내기 기능이 추가되지 않았으며(원래 의도했던 기능이지만) 현재는 쿼리만 지원합니다.

테스트 중에 4022 오류가 발생하는 경우, 그렇다면 테스터는 내보내기 파일 크기에 제한이 있습니다(디스크에 기록되는 데이터의 총 크기 1GB).

데이터베이스 내보내기 함수에서 테이블 이름 대신 쿼리를 지정하면 테스터 없이 오류 4022가 나타납니다.

데이터베이스의 크기가 10Mb 미만인 경우 이 기능을 사용하여 디스크의 데이터베이스에서 메모리의 데이터베이스로 데이터를 복사할 계획이었습니다.
 
Ilyas #:
쿼리가 작동하고 경로가 올바른지 확인하십시오.

고마워요, 경로를 다르게 제공하려고 시도하지만 실제로 SQLiteStudio에서 지정된 경로의 쿼리가 작동하고 터미널 로그에 쿼리를 출력 한 다음 문제없이 SQLiteStudio에서 복사하여 실행합니다.

결과에 대해 작성하겠습니다.

 
RAM에서 이름으로베이스에 연결할 수 있는지, 일반 캐시 매개 변수를 사용할 경우 SQLite에 그러한 가능성이있는 것으로 알고 있는데 MT5에서 활성화되어 있는지 알고 싶습니다.
 

데이터베이스에 대한 멀티 스레드 쓰기를 테스트하고 스크립트의 여러 복사본을 실행하며 각 복사본에는 expert_id 매개변수로 레이블을 지정할 수 있습니다.

#property copyright "Aliaksandr Hryshyn"
#property link      "https://www.mql5.com/ko/users/greshnik1"
#property version   "1.00"
#property script_show_inputs

enum e_E
  {
   e_0,
   e_1,
   e_2,
   e_3,
  };
input e_E expert_id=0;
//+------------------------------------------------------------------+
//| 스크립트 프로그램 시작 기능|
//+------------------------------------------------------------------+
void OnStart()
  {
   int db_handle=DatabaseOpen("tmp//test.sqlite",DATABASE_OPEN_READWRITE|DATABASE_OPEN_CREATE|DATABASE_OPEN_COMMON);
   const string sql_create=
      "CREATE TABLE IF NOT EXISTS Demo("
      "Id INTEGER PRIMARY KEY AUTOINCREMENT,"
      "Expert_id INTEGER,"
      "demo_0 TEXT(2000),"
      "demo_1 TEXT(2000),"
      "demo_2 TEXT(2000),"
      "demo_3 TEXT(2000),"
      "demo_4 TEXT(2000),"
      "demo_5 TEXT(2000),"
      "demo_6 TEXT(2000),"
      "demo_7 TEXT(2000)"
      ");";
   const string sql_add=
      "INSERT INTO Demo(Expert_id,demo_%s) VALUES(%s,'%s')";
   if(!DatabaseExecute(db_handle,sql_create))//없는 경우 테이블 생성
     {
      DatabaseClose(db_handle);
      Print("오류:",GetLastError());
      Print("쿼리:",sql_create);
      return;
     }
   string s1;
   string sql;
   int err_counter=100;//추가 오류 카운터 기록
   for(int i1=0; i1<1000; i1++)
     {
      s1="";
      for(int i2=0; i2<100; i2++)
        {
         s1+=string(MathRand());
        }
      sql=StringFormat(sql_add,string(MathRand()%8),string(expert_id),s1);
      if(DatabaseExecute(db_handle,sql))//데모... 세트에서 임의의 열에 레코드를 추가합니다.
        {
         err_counter=100;
        }
      else
        {
         if(err_counter==0)
           {
            DatabaseClose(db_handle);
            Print(expert_id,": end");
            return;
           }
         else
           {
            Print(expert_id,": ",err_counter);
            err_counter--;
            i1--;
           }
        }
      if(IsStopped())
         break;
      Sleep(1);// 약간의 수면
     }
   DatabaseClose(db_handle);
  }

모든 것이 올바르게 기록됩니다:


하지만 차단에 대한 오류가 발생합니다:

...
2021.09.18 13:08:05.252 Test_sql (EURUSD,M1)    2: 80
2021.09.18 13:08:05.267 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.267 Test_sql (EURUSD,M1)    2: 79
2021.09.18 13:08:05.283 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.283 Test_sql (EURUSD,M1)    2: 78
2021.09.18 13:08:05.299 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.299 Test_sql (EURUSD,M1)    1: 100
2021.09.18 13:08:05.315 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.315 Test_sql (EURUSD,M1)    1: 99
...

어떻게 해야 하나요? 오류를 반환하지 않고 조건부 레코드를 삽입하는 메커니즘이 있어야 합니다.

 
Ilyas #:
쿼리가 작동해야 하며 경로가 올바른지 확인하세요.

1. 데이터베이스 연결이 작동하는지 확인했습니다!

문제는 다음과 같았습니다. RAM에서 생성 된베이스에 연결하려고했는데이 경우 물리적베이스는 ATTACH DATABASE가 작동하지 않지만 RAM베이스를 물리적베이스에 연결하면 작동합니다!

이것은 RAM에베이스의 사본을 만들기에 충분하므로 계산 속도가 빨라집니다))).


2. 나는 더 나아가기로 결정했습니다... 한 가지 가능성을 더 확인하기로 결정했습니다:

'file:memdb1?mode=memory&cache=shared'를 M으로 데이터베이스에 연결합니다;

아이디어에 따르면 데이터베이스는 RAM에 생성되고 스레드가 닫힌 후 존재하지 않아야하지만 그 동작은 다릅니다 ...

1에서는 모든 MQL5 프로그램, 전문가 조언자, 지표, 스크립트, 서비스에서 참여할 수 있습니다,

2에서는 재부팅 후에도 그 안에있는 데이터가 영원히 저장됩니다. 나는 이미 데이터베이스가 물리적으로 생성되었을 수도 있다고 생각했지만 * memdb1 *이라는 이름으로 검색해도아무것도 찾지 못 했습니다.

추신 아마도 내가 지표에서베이스를 만들었고 공통 스레드에서 작동하기 때문일까요?


이것은 멋진 기능이지만 다음 업데이트와 이에 대한 내 메시지 이후에도 터미널에 남아 있는지 알고 싶습니다 : )))).

이 경우 문제와 지연없이 프로그램간에 많은 양의 데이터를 쉽게 전송할 수 있으며 이름 길이로 제한된 전역 변수를 사용하지 않습니다.....


이 실행에서는 MQL5 프로그램이 완료된 후 삭제됩니다:

ATTACH DATABASE ':memory:?cache=shared' AS M;

ATTACH DATABASE ':memory:' AS M;

 

안녕하세요!

MT 개발자에게 질문 : 다른 프로젝트에서 경험 한 결과 이것이 오류의 원인 인 데이터베이스 오류 , 데이터베이스가 잠겨 있다고 판단하여 SQLite 라이브러리의 공유 속성을 비활성화 할 수 있습니까?

다른 스레드에서 데이터베이스에 액세스하는 경우 데이터베이스 자체 수준에서, 즉 데이터베이스를 연 직후 다음 두 쿼리를 실행하면 모두 해결됩니다:

1. PRAGMA journal_mode = WAL;

2. PRAGMA busy_timeout = 1000;

하지만 잠금 오류는 기본을 공유가 아닌 상태로 만들어야만 사라지며 , 쿼리로 해결할 수는 없습니다 .

 
Daniil Kurmyshev 프로젝트의 경험에 따라 이것이 오류의 원인 인 것으로 판단되는 경우 SQLite 라이브러리의 공유 속성을 비활성화 할 수 있습니까? 데이터베이스 오류, 데이터베이스가 잠겨 있습니다.

다른 스레드에서 데이터베이스에 액세스하는 경우 데이터베이스 자체 수준에서, 즉 데이터베이스를 연 직후에 이 두 쿼리를 실행하여 모두 해결됩니다:

1. PRAGMA journal_mode = WAL;

2. PRAGMA busy_timeout = 1000;

하지만 잠금 오류는 베이스를 공유가 아닌 상태로 만들어야만 사라지며 쿼리로는 해결할 수 없습니다 .

이 경우 쿼리 속도가 떨어지고 메모리 요구 사항이 증가합니다....

하지만 모든 것이 괜찮습니다 :-)

SQLite는 하나의 스레드 또는 하나의 작성자와 많은 독자를 위해 설계되었습니다. 많은 작가는 그것에 관한 것이 아니라 "가볍지"않은 다른 기반에 관한 것입니다.

MQL에 관한 것이 아니라 실제로 모든 곳에서 사용되는 방식입니다.