"SQLite: MQL5'te SQL veritabanlarıyla yerel olarak çalışma" makalesi için tartışma - sayfa 8

 

Ve 2. soru:

SQLite'ın yerleşik mekanizmasını kullanarak veritabanları arasında veri aktarmak için ATTACH/DETACH işlevlerini kullanmaya çalıştığımda, sonuç 5601 işlem hatası oluyor...

Aynı işlemi SQLiteStudio'da çalıştırırken her şey yolunda.

Bu bilerek mi yapılıyor yoksa bir şeyler mi çalışmıyor?

   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 program yürütme iptali), muhtemelen MQL işlevi içinde hata, kütüphanemdeki kodun bir parçası:


Ne yazık ki, DatabaseExport işlevi tabloyu dışa aktarma işlevselliğini almamıştır (bu işlevsellik başlangıçta amaçlanmış olmasına rağmen) ve şu anda yalnızca sorguları desteklemektedir.

Hata 4022'de, test sırasında mı alıyorsunuz, evet ise, test cihazının dışa aktarma dosyası boyutunda bir sınırlaması vardır - diske yazılan toplam veri boyutu 1 GB ?

 
Daniil Kurmyshev SQLite'ın dahili mekanizması ile veritabanları arasında veri aktarmak için ATTACH/DETACH fonksiyonlarını kullanmaya çalışıyorum, sonuç işlem hatası 5601...

Aynı işlemi SQLiteStudio'da yürütürken her şey yolunda.

Bu bilerek mi yapılıyor yoksa bir şey mi çalışmıyor?

Sorgu çalışmalıdır, yolların doğru olup olmadığını kontrol edin
 
Ilyas #:

Ne yazık ki, DatabaseExport işlevi hiçbir zaman tablo dışa aktarma işlevine sahip olmamıştır (bu işlev başlangıçta amaçlanmış olmasına rağmen) ve şu anda yalnızca sorguları desteklemektedir.

4022 hatasını test sırasında mı alıyorsunuz, evet ise, test cihazının dışa aktarma dosya boyutu üzerinde bir sınırlaması vardır - diske yazılan toplam veri boyutu 1 GB ?

DatabaseExport işlevinde tablo adı yerine sorgu belirtirseniz, test cihazı olmadan 4022 hatası görünür.

Veritabanının boyutu 10 Mb'den az, bu işlevi diskteki veritabanından bellekteki veritabanına veri kopyalamak için kullanmayı planlıyordum.
 
Ilyas #:
Sorgu çalışmalıdır, yolların doğru olup olmadığını kontrol edin

Teşekkürler, yolu farklı bir şekilde sağlamaya çalışacağım, ancak aslında SQLiteStudio'da belirtilen yoldaki sorgu çalışıyor, sorguyu terminal günlüğüne çıkardım ve ardından SQLiteStudio'da sorunsuz bir şekilde kopyalayıp çalıştırdım.

Sonuç hakkında yazacağım.

 
RAM'deki tabana isme göre bağlanma ve genel önbelleğin parametresini kullanma imkanı var mı, SQLite 'ın böyle bir imkanı olduğunu biliyorum, ancak MT5'e dahil olup olmadığını bilmek istiyorum, teşekkür ederim.
 

Veritabanına çok iş parçacıklı yazmayı test edin, betiğin birden fazla kopyasını çalıştırın, her kopya expert_id parametresiyle etiketlenebilir.

#property copyright "Aliaksandr Hryshyn"
#property link      "https://www.mql5.com/tr/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;
//+------------------------------------------------------------------+
//| Komut dosyası programı başlatma işlevi|
//+------------------------------------------------------------------+
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))//Değilse tablo oluştur
     {
      DatabaseClose(db_handle);
      Print("Hata:",GetLastError());
      Print("Sorgu:",sql_create);
      return;
     }
   string s1;
   string sql;
   int err_counter=100;//Kayıt ekleme hata sayacı
   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))//Demo_... setinden rastgele bir sütuna bir kayıt ekleyin.
        {
         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);// Birazcık uyku
     }
   DatabaseClose(db_handle);
  }

Her şey doğru şekilde yazılıyor:


Ancak bloklama ile ilgili hatalar alıyorum:

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

Nasıl olmalı? Hata döndürmeden koşullu kayıt ekleme mekanizması olmalıdır.

 
Ilyas #:
Sorgu çalışmalıdır, yolların doğru olduğundan emin olun

1. Kontrol edildi ATTACH DATABASE çalışıyor!

Sorun şu şekildeydi, RAM'de oluşturulan tabana eklemeye çalıştım, bu durumda fiziksel taban ATTACH DATABASE çalışmıyor, ancak RAM tabanını fiziksel tabana eklersek çalışıyor!

Bu, RAM'de tabanın bir kopyasını oluşturmam için oldukça yeterli, bu da hesaplamaları hızlandırıyor)))


2. Daha ileri gitmeye karar verdim. ve bir olasılığı daha kontrol etmeye karar verdim:

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

Fikre göre, veritabanı RAM'de oluşturulmalı ve iş parçacığı kapatıldıktan sonra varlığı sona ermelidir, ancak davranışı farklıdır ...

1'de, herhangi bir MQL5 programından, Uzman Danışmanından, göstergeden, komut dosyasından, hizmetten katılabilirim,

2'de, içindeki veriler yeniden başlatıldıktan sonra bile sonsuza kadar kaydedilir, zaten düşündüm ... belki de veritabanı fiziksel olarak oluşturulmuştur, ancak *memdb1* adıyla yapılan bir aramahiçbir şey bulamadı

Not: Belki de tabanı göstergeden oluşturduğum ve ortak bir iş parçacığında çalıştığı içindir?


Bu harika bir özellik, ancak bir sonraki güncellemelerde ve bu konudaki mesajımdan sonra terminalde kalıp kalmayacağını bilmek istiyorum: )))).

Bu durumda, programlar arasında büyük miktarda veriyi sorunsuz ve gecikmesiz olarak kolayca aktarabilir ve ad uzunluğu ile sınırlı global değişkenleri kullanmazsınız....


Bu uygulamada MQL5 programı bittikten sonra silinir:

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

ATTACH DATABASE ':memory:' AS M;

 

İyi günler!

MT geliştiricilerine soru, SQLite kütüphanesinin Paylaşılan özelliğini devre dışı bırakmak mümkün mü, diğer projelerdeki deneyimlerle bunun hatanın nedeni olduğu belirlendi: veritabanı hatası , veritabanı kilitli.

Veritabanına farklı iş parçacıklarından erişiyorsanız, veritabanının kendi düzeyinde, yani veritabanını açtıktan hemen sonra bu iki sorguyu çalıştırarak çözülür:

1. PRAGMA journal_mode = WAL;

2. PRAGMA busy_timeout = 1000;

ancak kilitleme hatası yalnızca tabanı Paylaşılmayan yaptıktan sonra ortadan kalkacaktır , bunu sorgularla yapamazsınız .

 
Daniil Kurmyshev projelerdeki deneyimlerle bunun hatanın nedeni olduğu belirlendi: veritabanı hatası, veritabanı kilitli.

Eğer veritabanına farklı iş parçacıklarından erişim varsa, bu sorun veritabanının kendi seviyesinde, yani veritabanı açıldıktan hemen sonra bu iki sorgunun çalıştırılmasıyla çözülür:

1. PRAGMA journal_mode = WAL;

2. PRAGMA busy_timeout = 1000;

ancak kilitleme hatası yalnızca tabanı Paylaşılmayan yaptıktan sonra ortadan kalkacaktır , bunu sorgularla yapamazsınız .

Bu durumda sorguların hızı düşecek ve bellek gereksinimleri artacaktır....

ama her şey yolunda :-)

SQLite bir iş parçacığı ya da bir yazar ve birçok okuyucu için tasarlanmıştır. Birçok yazar bu konuda değil, bu konuda "hafif" olmayan diğer üsler.

Bu MQL ile ilgili değil - bu sadece gerçekten ve her yerde olduğu gibi.