Diskussion zum Artikel "SQLite: Natives Arbeiten mit SQL-Datenbanken in MQL5" - Seite 8

 

Und Frage #2:

Wenn ich versuche, die ATTACH/DETACH-Funktionen zu verwenden, um Daten zwischen Datenbanken mit dem in SQLite eingebauten Mechanismus zu übertragen, ist das Ergebnis ein Transaktionsfehler 5601...

Wenn ich die gleiche Transaktion in SQLiteStudio ausführe, ist alles in Ordnung.

Ist dies absichtlich geschehen oder funktioniert etwas nicht?

   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 Programmausführung), wahrscheinlich ein Fehler innerhalb der MQL-Funktion, ein Teil des Codes aus meiner Bibliothek:


Leider hat die DatabaseExport-Funktion die Tabellenexportfunktionalität nicht erhalten (obwohl diese Funktionalität ursprünglich vorgesehen war) und unterstützt derzeit nur Abfragen.

Der Fehler 4022 tritt beim Testen auf, wenn ja, hat der Tester eine Beschränkung der Exportdateigröße - 1 GB Gesamtgröße der auf die Festplatte geschriebenen Daten?

 
Daniil Kurmyshev SQLite zu übertragen. Das Ergebnis ist der Transaktionsfehler 5601...

Wenn ich die gleiche Transaktion in SQLiteStudio ausführe, ist alles in Ordnung.

Ist dies beabsichtigt oder funktioniert etwas nicht?

Die Abfrage sollte funktionieren, überprüfen Sie, ob die Pfade korrekt sind
 
Ilyas #:

Leider hat die Funktion DatabaseExport nie die Funktionalität des Tabellenexports erhalten (obwohl diese Funktionalität ursprünglich vorgesehen war) und unterstützt derzeit nur Abfragen.

Tritt der Fehler 4022 beim Testen auf? Wenn ja, hat der Tester eine Beschränkung der Exportdateigröße - 1 GB Gesamtgröße der auf die Festplatte geschriebenen Daten.

Der Fehler 4022 tritt auch ohne Tester auf, wenn Sie in der Funktion DatabaseExport statt des Tabellennamens eine Abfrage angeben.

Die Größe der Datenbank beträgt weniger als 10 MB, ich wollte diese Funktion nutzen, um Daten aus der Datenbank auf der Festplatte in die Datenbank im Speicher zu kopieren.
 
Ilyas #:
Die Abfrage sollte funktionieren, überprüfen Sie, ob die Pfade korrekt sind

Danke, ich werde versuchen, den Pfad anders anzugeben, aber in der Tat funktioniert in SQLiteStudio die Abfrage unter dem angegebenen Pfad, ich gebe die Abfrage in das Terminalprotokoll aus und kopiere und führe sie dann in SQLiteStudio ohne Probleme aus.

Ich werde über das Ergebnis schreiben.

 
Gibt es eine Möglichkeit, sich mit der Basis im RAM nach Namen zu verbinden und den Parameter des allgemeinen Cache zu verwenden, ich weiß, dass SQLite eine solche Möglichkeit hat, aber ich würde gerne wissen, ob sie in MT5 enthalten ist, danke.
 

Testen Sie das Schreiben in die Datenbank mit mehreren Threads, führen Sie mehrere Kopien des Skripts aus, wobei jede Kopie mit dem Parameter expert_id gekennzeichnet werden kann.

#property copyright "Aliaksandr Hryshyn"
#property link      "https://www.mql5.com/de/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;
//+------------------------------------------------------------------+
//| Skript-Programmstartfunktion|
//+------------------------------------------------------------------+
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))//Tabelle erstellen, falls nicht vorhanden
     {
      DatabaseClose(db_handle);
      Print("Fehler:",GetLastError());
      Print("Abfrage:",sql_create);
      return;
     }
   string s1;
   string sql;
   int err_counter=100;//Satzadditionsfehlerzähler
   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))//Hinzufügen eines Datensatzes zu einer zufälligen Spalte aus dem demo_... Set.
        {
         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);// Ein bisschen Schlaf
     }
   DatabaseClose(db_handle);
  }

Alles wird korrekt geschrieben:


Aber ich erhalte Fehler beim Blockieren:

...
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
...

Es sollte einen Mechanismus für das bedingte Einfügen von Datensätzen geben, ohne dass ein Fehler zurückgegeben wird.

 
Ilyas #:
Die Abfrage sollte funktionieren, stellen Sie sicher, dass die Pfade korrekt sind

1. Überprüft ATTACH DATABASE funktioniert!

Das Problem war in der folgenden, versuchte ich, um die Basis in RAM erstellt anhängen, die physische Basis in diesem Fall ATTACH DATABASE funktioniert nicht, aber wenn wir die RAM-Basis auf die physische Basis anhängen, es funktioniert!

Das reicht mir völlig aus, um eine Kopie der Basis im RAM zu erstellen, was die Berechnungen beschleunigt)))


2. Ich beschloss, noch weiter zu gehen... und eine weitere Möglichkeit zu prüfen, nämlich:

ATTACH DATABASE 'file:memdb1?mode=memory&cache=shared' AS M;

Nach der Idee sollte die Datenbank im RAM erstellt werden und nach dem Schließen des Threads nicht mehr existieren, aber das Verhalten ist anders...

In 1 kann ich ihr von jedem MQL5-Programm, Expert Advisor, Indikator, Skript, Dienst aus beitreten,

In 2 werden die Daten darin für immer gespeichert, auch nach einem Neustart, ich dachte schon ... dass die Datenbank vielleicht physisch erstellt wird, aber eine Suche nach dem Namen *memdb1*hat nichts gefunden

P.S. Vielleicht liegt es daran, dass ich die Basis aus dem Indikator erstellt habe, und es funktioniert in einem gemeinsamen Thread?


Es ist ein cooles Feature, aber ich würde gerne wissen, ob es in den nächsten Updates und nach meiner Nachricht darüber im Terminal bleiben wird:))).

In diesem Fall können Sie leicht große Datenmengen zwischen Programmen übertragen, ohne Probleme und Verzögerungen, und verwenden Sie keine globalen Variablen durch die Länge des Namens begrenzt....


Bei einer solchen Ausführung wird er nach Beendigung des MQL5-Programms gelöscht:

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

ATTACH DATABASE ':memory:' AS M;

 

Guten Tag!

Frage an die MT-Entwickler, ist es möglich, das Shared-Attribut der SQLite-Bibliothek zu deaktivieren, durch Erfahrung in anderen Projekten festgestellt, dass dies die Ursache für den Fehler ist: Datenbankfehler, Datenbank ist gesperrt.

Wenn Sie von verschiedenen Threads auf die Datenbank zugreifen, wird das Problem auf der Ebene der Datenbank selbst gelöst, nämlich durch die Ausführung dieser beiden Abfragen unmittelbar nach dem Öffnen der Datenbank:

1) PRAGMA journal_mode = WAL;

2. pRAGMA busy_timeout = 1000;

aber der Sperrfehler verschwindet nur, wenn Sie die Basis nicht freigegeben haben, Sie können das nicht mit Abfragen erreichen.

 
Daniil Kurmyshev Projekten festgestellt, dass dies die Ursache für den Fehler ist: Datenbankfehler, Datenbank ist gesperrt.

Wenn der Zugriff von verschiedenen Threads auf die Datenbank ist, ist es alle auf der Ebene der Datenbank selbst gelöst, nämlich durch die Ausführung dieser beiden Abfragen unmittelbar nach dem Öffnen der Datenbank:

1) PRAGMA journal_mode = WAL;

2. pRAGMA busy_timeout = 1000;

aber der Sperrfehler verschwindet nur, wenn Sie die Basis nicht freigegeben haben, das geht nicht mit Abfragen.

In diesem Fall wird die Geschwindigkeit der Abfragen sinken und der Speicherbedarf steigen....

aber es ist alles in Ordnung :-)

SQLite ist für einen Thread oder einen Schreiber und viele Leser ausgelegt. Viele Schreiber sind es nicht, dafür andere Grundlagen, die nicht "leicht" sind.

es geht nicht um MQL - es ist einfach so, wie es wirklich und überall ist.