Sekizinci saniyədə bir saniyədə SQLite performansını artırmaq?

SQLite'yi optimallaşdırmaq çətindir. C-tətbiqində edilən investisiyalar saniyədə 85 əlavədən saniyədə 96,000-dən çox əlavəyə dəyişə bilər!

Ümumi məlumat: Biz masa üstü tətbiqinin bir hissəsi kimi SQLite istifadə edirik. XML fayllarında saxlanılan konfiqurasiya məlumatlarının böyük bir miqdarı var və tətbiq başlandıqda daha çox emal üçün SQLite veritabanına yüklənir və yüklənir. SQLite bu vəziyyət üçün idealdır, çünki sürətli, xüsusi konfiqurasiya tələb etmir və verilənlər bazası diskdə bir fayl olaraq saxlanılır.

Məqsəd: İlk növbədə gördüyümdən məyus oldum. Verilənlər bazasının necə konfiqurasiyasına və API-nı necə istifadə etdiyinə görə, SQLite performansının əhəmiyyətli dərəcədə dəyişə biləcəyi (həm toplu əlavələr, həm də onların seçimi üçün). Bütün variantlar və metodların nə olduğunu öyrənmək üçün çətin bir sual yox idi, buna görə də mən bu tədqiqatla əlaqəli problemlərdən qorunmaq üçün on123.ru oxucusundan istifadə edərək nəticəni bölüşmək üçün wiki icmasında bu giriş yaratmağı ağıllandırdım.

Təcrübə: Ümumi mənada (yəni "əməliyyatın istifadə edin!") Performans göstərişləri barədə söhbət etmək əvəzinə, bəzi C kodunu yazmaq və müxtəlif variantların təsirini ölçmək daha yaxşı olardı. Biz sadə məlumatlarla başlayırıq:

  • 28 MB TAB məhdudlaşdıran mətn faylı (təqribən 865,000 qeyd) Toronto şəhərinin tam tarif planı
  • Mənim sınaq maşınım Windows XP-də çalışan 3.6 GHz P4-dir.
  • Kod Visual C ++ 2005 ilə "Full Optimization" (/ Ox) ilə "Release" kimi tərtib edilir və Fast Code (/ Ot) istifadə edir.
  • SQLite "Amalgamation" istifadə edirəm, birbaşa test proqramına daxil edilir. Daxil etdiyim SQLite versiyası bir az daha yaşlıdır (3.6.7), amma şübhələnirəm ki, bu nəticələr son versiyaya görə müqayisə ediləcəkdir (əks halda düşünsəniz, şərh verin).

Kodu yaz!

Kod: Xətt vasitəsilə bir mətn faylı xəttini oxuyan sadə bir C proqramı dəyərləri bir xətt təşkil edir və məlumatları SQLite verilənlər bazasına daxil edir. Kodun bu "əsas" versiyasında bir verilənlər bazası yaradılır, amma həqiqətən məlumatları daxil etməyəcəyik:

  #include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> #include "sqlite3.h" #define INPUTDATA "C:\\TTC_schedule_scheduleitem_10-27-2009.txt" #define DATABASE "c:\\TTC_schedule_scheduleitem_10-27-2009.sqlite" #define TABLE "CREATE TABLE IF NOT EXISTS TTC (id INTEGER PRIMARY KEY, Route_ID TEXT, Branch_Code TEXT, Version INTEGER, Stop INTEGER, Vehicle_Index INTEGER, Day Integer, Time TEXT)" #define BUFFER_SIZE 256 int main(int argc, char **argv) { sqlite3 * db; sqlite3_stmt * stmt; char * sErrMsg = 0; char * tail = 0; int nRetCode; int n = 0; clock_t cStartClock; FILE * pFile; char sInputBuf [BUFFER_SIZE] = "\0"; char * sRT = 0;  char * sBR = 0;  char * sVR = 0;  char * sST = 0;  char * sVI = 0;  char * sDT = 0;  char * sTM = 0;  char sSQL [BUFFER_SIZE] = "\0";   sqlite3_open(DATABASE,  sqlite3_exec(db, TABLE, NULL, NULL,cStartClock = clock(); pFile = fopen (INPUTDATA,"r"); while (!feof(pFile)) { fgets (sInputBuf, BUFFER_SIZE, pFile); sRT = strtok (sInputBuf, "\t");  sBR = strtok (NULL, "\t");  sVR = strtok (NULL, "\t");  sST = strtok (NULL, "\t");  sVI = strtok (NULL, "\t");  sDT = strtok (NULL, "\t");  sTM = strtok (NULL, "\t");   n++; } fclose (pFile); printf("Imported %d records in %4.2f seconds\n", n, (clock() - cStartClock) / (double)CLOCKS_PER_SEC); sqlite3_close(db); return 0; } 

"Nəzarət"

As kodunu yerinə yetirərkən həqiqətən verilənlər bazasında heç bir əməliyyata ehtiyac yoxdur, amma bu bizə qaynaq kodunun C və simli ilə çıxış-çıxış əməliyyatları nə qədər sürətli bir fikir verəcəkdir.

İdxal 864913 qeydləri 0.94 saniyə

Böyüklər! Əslində hər hansı bir əlavə etmədiyimiz təqdirdə saniyədə 920,000 əlavə edə bilərik: -)


"Ən pis vəziyyət ssenari"

Sqlite3_exec istifadə edərək, bu SQL əməliyyatını fayldan oxuyan dəyərləri istifadə edərək, bir SQL sətri yaratmaq niyyətindəyik:

 sprintf(sSQL, "INSERT INTO TTC VALUES (NULL, '%s', '%s', '%s', '%s', '%s', '%s', '%s')", sRT, sBR, sVR, sST, sVI, sDT, sTM); sqlite3_exec(db, sSQL, NULL, NULL, > 

Hər bir əlavə üçün VDBE koduna kompilyasiya ediləcək və hər bir əlavə öz əməliyyatında baş verəcəkdir, çünki bu yavaş olacaq. Necə yavaş?

İthal 864913 saniyede 9933.61 saniyədə qeyd

Clap! 2 saat 45 dəqiqə! Bu saniyədə yalnız 85 əlavədir.

Əməliyyatdan istifadə

Default olaraq, SQLite hər bir INSERT / UPDATE bəyanatında unikal bir əməliyyatda qiymətləndirəcəkdir. Çox sayda əlavələr icra edərsəniz, əməliyyatda bir əməliyyat etmək məsləhət görülür:

 sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL,  pFile = fopen (INPUTDATA,"r"); while (!feof(pFile)) { ... } fclose (pFile); sqlite3_exec(db, "END TRANSACTION", NULL, NULL, > 

38.03 saniyə ərzində 864913-ə daxildir

Bu daha yaxşıdır. Sadəcə olaraq, bütün əlavələrimizi vahid bir əməliyyatda köçürmək bizim performansımızı saniyədə 23,000 əlavəyə çevirdi .

Hazırlanmış bəyanatı istifadə edin

Bir əməliyyatdan istifadə böyük bir yaxşılaşma idi, amma hər bir əlavə üçün SQL bəyannaməsini yenidən tərtib etmək eyni və artıq SQL kodunu istifadə edərkən məntiqli deyil. sqlite3_prepare_v2 bizim SQL sqlite3_prepare_v2 bir dəfə tərtib etmək üçün istifadə edək və sonra parametrlərimizi sqlite3_bind_text istifadə edərək bu ifadəyə sqlite3_bind_text :

  cStartClock = clock(); sprintf(sSQL, "INSERT INTO TTC VALUES (NULL, @RT, @BR, @VR, @ST, @VI, @DT, @TM)"); sqlite3_prepare_v2(db, sSQL, BUFFER_SIZE,   sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL,  pFile = fopen (INPUTDATA,"r"); while (!feof(pFile)) { fgets (sInputBuf, BUFFER_SIZE, pFile); sRT = strtok (sInputBuf, "\t");  sBR = strtok (NULL, "\t");  sVR = strtok (NULL, "\t");  sST = strtok (NULL, "\t");  sVI = strtok (NULL, "\t");  sDT = strtok (NULL, "\t");  sTM = strtok (NULL, "\t");  sqlite3_bind_text(stmt, 1, sRT, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, sBR, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, sVR, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 4, sST, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 5, sVI, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 6, sDT, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 7, sTM, -1, SQLITE_TRANSIENT); sqlite3_step(stmt); sqlite3_clear_bindings(stmt); sqlite3_reset(stmt); n++; } fclose (pFile); sqlite3_exec(db, "END TRANSACTION", NULL, NULL,  printf("Imported %d records in %4.2f seconds\n", n, (clock() - cStartClock) / (double)CLOCKS_PER_SEC); sqlite3_finalize(stmt); sqlite3_close(db); return 0; 

İthal 864913 16.27 saniyede qeyd edir

Gözəl! Bir az daha kod var ( sqlite3_clear_bindingssqlite3_reset sqlite3_clear_bindings unutmayın), ancaq performansımızı saniyədə 53.000 sqlite3_reset .

PRAGMA sinxron = OFF

Default olaraq, SQLite OS səviyyəsində bir yazma əmri verildikdən sonra dayandırır. Bu məlumatların diskə yazılmasını təmin edir. synchronous = OFF , SQLite-ə yazı yazmaq üçün sadəcə məlumatları OS-yə köçürməyi və sonra da davam etdirməyi əmr edirik. Bəzi verilənlər bazası faylın plakaya yazılmasından əvvəl kompüter fəlakətli bir uğursuzluq (və ya elektrik kəsilməsi) olduqda zədələnə biləcəyi ehtimalı var:

  sqlite3_open(DATABASE,  sqlite3_exec(db, TABLE, NULL, NULL,  sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, > 

İxrac 864913 12.41 saniyə qeyd

İnkişaflar indi daha kiçikdir, ancaq saniyədə 69.600 ədəd ediləcək.

PRAGMA journal_mode = MEMORY

PRAGMA journal_mode = MEMORY nəzərə alaraq PRAGMA journal_mode = MEMORY saxlamağı düşünün. Əməliyyatınız daha sürətli olacaq, amma gücünüzü ləğv etsəniz və ya bir əməliyyat zamanı proqramınız uğursuz olarsa, məlumat bazasını qismən tamamlanmış bir əməliyyatla zədələnmiş bir vəziyyətdə buraxa bilərsiniz:

  sqlite3_open(DATABASE,  sqlite3_exec(db, TABLE, NULL, NULL,  sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, > 

İthal 864913 13.50 saniyede qeyd edir

Əvvəlki optimallaşdırmadan bir az yavaş, saniyədə 64 min əlavələr.

PRAGMA sinxron = OFF və PRAGMA journal_mode = MEMORY

Əvvəlki iki optimizasyonu birləşdirin. Bu bir az riskli (uğursuzluq halında), amma sadəcə məlumatları idxal edirik (bankı idarə etmirik):

  sqlite3_open(DATABASE,  sqlite3_exec(db, TABLE, NULL, NULL,  sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL,  sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, > 

864913 qeydləri 12.00 saniyə hesablandı

Fantastic! Saniyədə 72 min ədəd əlavə edəcəyik .

Yaddaşlı verilənlər bazasını istifadə edin

Yalnız tətillər üçün bütün əvvəlki optimallaşdırmalara əsaslanır və verilənlər bazası faylının adını yenidən müəyyənləşdirin, belə ki, biz RAM-da tam işləyirik:

 #define DATABASE ":memory:" 

İthal 864913 10.94 saniyede qeyd edir

Verilənlər bazasını RAM-da saxlamağa üstünlük vermir, ancaq, saniyədə 79 min ədəd əlavə edəcəyimiz təəssürat yaradır .

C kodunu refactoring

Bu SQLite üçün xüsusi bir inkişaf olmasa da, while char* in əlavə atama əməliyyatları sevmirəm. Birbaşa strtok() çıxışını keçmək üçün bu kodu tez bir zamanda yenidən təşkil edək və kompilyator prosesi sürətləndirməyə sqlite3_bind_text() :

 pFile = fopen (INPUTDATA,"r"); while (!feof(pFile)) { fgets (sInputBuf, BUFFER_SIZE, pFile); sqlite3_bind_text(stmt, 1, strtok (sInputBuf, "\t"), -1, SQLITE_TRANSIENT);  sqlite3_bind_text(stmt, 2, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  sqlite3_bind_text(stmt, 3, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  sqlite3_bind_text(stmt, 4, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  sqlite3_bind_text(stmt, 5, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  sqlite3_bind_text(stmt, 6, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  sqlite3_bind_text(stmt, 7, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);  sqlite3_step(stmt);  sqlite3_clear_bindings(stmt);  sqlite3_reset(stmt);  n++; } fclose (pFile); 

Qeyd Gerçək verilənlər bazası faylını istifadə edəcəyik. Yaddaş verilənlər bazası sürətli, amma mütləq praktik deyil.

8.94 saniyə ərzində 864913-ə qeydlər daxildir

Parametrləri birləşdirərkən istifadə olunan simli işləmə kodu üçün bir az refactoring bizə saniyədə 96,700 əlavə əlavə etməyə imkan verdi . İnanıram ki, bu, çox tezdir. Digər dəyişənləri (yəni səhifə ölçüsü, indeksin yaradılması və s.) Dəyişməyə başlayanda, bu bizim kriteriyəm.


Xülasə (hələ)

İnşallah sən hələ mənimlə olma! Bu yola düşdüklərimiz səbəbi, geniş məhsulun səmərəliliyinin SQLite-dən çox fərqləndiyini və işimizi sürətləndirmək üçün hansı dəyişikliklərin edilməsi lazım olduğuna dair hər zaman aydın deyil. Eyni kompilyator (və kompilyator variantları), SQLite və eyni məlumatın eyni versiyasını istifadə edərək, kodumuzu optimallaşdırdıq və SQLite- dən saniyədə ən çox 85 ədəd əlavə və saniyədə 96,000-dən çox əlavədən keçmək üçün istifadə etdilər!


INDEX yaradın, sonra INSERT vs. INSERT, sonra isə INDEX yaradın

SELECT fəaliyyətini ölçməyə başlamazdan əvvəl biz bilirik ki, indekslər yaradacağıq. Aşağıdakı cədvəllərdən birində, kütləvi əlavələr edərkən data yerləşdirildikdən sonra bir index yaratmaq daha sürətli olur (əvvəlcə bir indeksi yaratmaq və sonra məlumatların daxil edilməsi). Keçir:

Bir indeks yaradın və sonra məlumatları yapışdırın.

 sqlite3_exec(db, "CREATE INDEX 'TTC_Stop_Index' ON 'TTC' ('Stop')", NULL, NULL,  sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL,  ... 

18,13 saniyə içində 864913 qeydlər alındı

Veriyi yapışdırıb İndeks yaradın

 ... sqlite3_exec(db, "END TRANSACTION", NULL, NULL,  sqlite3_exec(db, "CREATE INDEX 'TTC_Stop_Index' ON 'TTC' ('Stop')", NULL, NULL, > 

İthal 864913, 13.66 saniyə qeyd

Gözlənildiyi kimi, bir sütun indeksləşdirildikdə həcmli əlavələr yavaş olur, lakin məlumatlar daxil edildikdən sonra indeks yaradıldığında əhəmiyyətlidir. İndeks olmadan bizim bazamız saniyədə 96 min əlavələrdir. Birinci indeksin yaradılması və sonra məlumatların daxil edilməsi bizə 47,700 ədəd əlavə verir, əvvəlcə məlumatların yerləşdirilməsi və sonra indeksi yaratmaq bizə saniyədə 63,300 əlavə verir.


Digər ssenarilərin təkliflərini qəbul etmək istərdim ... Və tezliklə SELECT sorguları üçün oxşar məlumatları tərtib edəcəyəm.

2620
11 нояб. Mike Willekes tərəfindən təyin olunan 11 noyabr. 2009-11-11 01:16 '09 at 1:16 pm 2009-11-11 01:16
@ 10 cavab

Bəzi məsləhətlər:

  1. Əlavə / yeniləməni əməliyyata daxil edin.
  2. pragma journal_mode köhnə versiyalarında, pragma journal_mode jurnalının daha az rejimini ( pragma journal_mode ) pragma journal_mode . NORMAL , sonra OS işə düşdüyündə verilənlər bazasının zədələnə biləcəyi üçün çox narahat olmağınız halında, əlavə sürətinizi əhəmiyyətli dərəcədə artıra bilən OFF var. Başvurunuz başarısız olursa, veriler doğru olmalıdır. Xahiş edirik yeni versiyalarda, OFF/MEMORY parametrləri tətbiq səviyyəsində çökmələr üçün təhlükəsiz deyildir.
  3. Səhifə ölçüsü oyunu da vacibdir ( PRAGMA page_size ). Böyük səhifə ölçüləri ilə, daha böyük səhifələr yaddaşda saxlanıldığından, oxumaq və yazmağı bir az daha sürətli edə bilərsiniz. Verilənlər bazası üçün daha çox yaddaş istifadə ediləcəyini unutmayın.
  4. Dizinleriniz varsa, bütün eklemlerinizi tamamladıktan sonra CREATE INDEX çağırırsınız. Bu, bir indeks yaratmaqdan və daha sonra əlavə etmədən daha sürətlidır.
  5. Bütün verilənlər bazası yazarkən kilidləndiyindən və bir neçə oxucu olmasına baxmayaraq, qeydlər kilidlənəcək, çünki SQLite-ə eyni vaxtda daxil olmağınız kifayət qədər ehtiyatlı olmalıdır. Bu SQLite yeni versiyalarında WAL əlavə ilə bir qədər yaxşılaşmışdır.
  6. Kosmik qənaətdən istifadə edin ... daha kiçik verilənlər bazaları daha sürətli getmək. Məsələn, bir cüt əsas dəyəriniz varsa, mümkün INTEGER PRIMARY KEY düyməsinə basaraq, masada nəzərdə tutulan təkrarlanan sütun sütununu əvəz edəcəkdir.
  7. Bir çox mövzu istifadə edirsinizsə, payı arasında yüklənmiş səhifələr mübadiləsi imkanı verən paylaşılan bir səhifə önbelleğini istifadə edərək qiymətli I / O zənglərindən qaçın.
  8. İstifadə etməyin !feof(file) !

Mən buradaburada da oxşar suallar verdim.

682
11 нояб. Cavab 11 noyabrda Snazzer tərəfindən verilir. 2009-11-11 06:45 '09 saat 06:45 'da 2009-11-11 06:45

Bu əlavələr üçün SQLITE_STATIC əvəzinə SQLITE_STATIC istifadə edin.

SQLITE_TRANSIENT , SQLITE_TRANSIENT qaytarmadan əvvəl verilmiş satırları kopyalamasına səbəb olacaq.

border=0

SQLITE_STATIC verdiyiniz yaddaş ünvanının sorgunun icra ediləcəyi qədər etibarlı SQLITE_STATIC bildirir (bu daima bu döngədə olduğu haldır). Bu, hər bir dövr üçün bir neçə əməliyyatı dağıtmaq, kopyalamaq və sərbəst buraxmağa imkan verir. Bəlkə də əhəmiyyətli bir inkişaf.

108
17 сент. Tiredofbuttons tərəfindən verilmiş cavab Sep 17 2014-09-17 19:47 '14 da 19:47 2014-09-17 19:47

Sqlite3_clear_bindings (stmt) çəkinin;

Sınaqdakı kod, hər dəfə kifayətlənməli olan bindings təşkil edir.

SQLite sənədlərindən API C API'ları

Sqlite3_step () 'i ilk dəfə və ya sqlite3_reset ()' dan hemen sonra çağırmadan əvvəl, bir sqlite3_bind () parametresine değer eklemek üçün bir proqramı çağırabilir. hər sqlite3_bind () zəng əvvəlki bağlamaları eyni parametrlə əvəz edir

(bax sqlite.org/cintro.html ). Dokümanlar üçün bu funksiya yoxdur , sadəcə bindings qoymaqla yanaşı onu çağırmalısınız.

Daha ətraflı: http://www.hoogli.com/blogs/micro/index.html#Avoid_sqlite3_clear_bindings ()

85
08 авг. Cavab verilir ahcox 08 aug. 2012-08-08 17:44 '12 at 17:44 2012-08-08 17:44

Toplu əlavələr

Bu mesajdan və məni buraya gətirən yığma daşqın sualından ilhamlandı - Bir dəfə SQLite verilənlər bazasına bir neçə satır qoymaq mümkündürmü? - İlk Git deposunu göndərdim:

https://github.com/rdpoor/CreateOrUpdate

MySQL , SQLite və ya PostgreSQL bir ActiveRecords array yükləyir. Mövcud yazıları gözardı etmək, onları yazmaq və ya bir səhv yaratmaq imkanı daxildir. Mənim qabiliyyətli testlərim, ardıcıl yazma ilə müqayisədə sürətdə 10 qat artım göstərir - YMMV.

Mən bunu böyük məlumat dəstləri idxal etmək üçün lazım olan istehsal kodunda istifadə edirəm və mən çox məmnunam.

49
20 мая '11 в 18:50 2011-05-20 18:50 Cavab qorxunc_fool tərəfindən verilir 20 May '08 18:50 2011-05-20 18:50

Əgər INSERT / UPDATE hesabatlarını poza bilə bilsəniz, toplu idxal ən yaxşı işləyir. 10.000 dəyərli bir dəyər, ya da mənim üçün bir neçə satır, YMMV ...

42
11 нояб. Cavab Leon 11 noyabr verilir. 2009-11-11 03:59 '09 at 3:59 pm 2009-11-11 03:59

Yalnız oxuduğunuza diqqət yetirsəniz, bir qədər daha sürətli (amma köhnəlmiş məlumatları oxuya bilərsiniz), versiyanı bir neçə axından bir neçə əlaqədən oxumaq lazımdır.

Əvvəlcə cədvəldə elementləri tapın:

  SELECT COUNT(*) FROM table 

sonra səhifələri oxuyun (LIMIT / OFFSET)

  SELECT * FROM table ORDER BY _ROWID_ LIMIT <limit> OFFSET <offset> 

hər bir mövzu üçün harada və hesablanır, məsələn:

 int limit = (count + n_threads - 1)/n_threads; 

hər axın üçün:

 int offset = thread_index * limit 

Kiçik (200 MB) verilənlər bazası üçün bu, 50-75% sürətləndirdi (Windows 7-də 3.8.0.2 64-bit). Bizim masalar çox normallaşmamışdır (1000-1500 sütun, təxminən 100.000 və ya daha çox satır).

Çox və ya çox az iş parçacığı bunu etməyəcək, özünüzü yoxlamaq və profilinizə ehtiyacınız var.

Həm də bizim üçün SHAREDCACHE performansı yavaşlatdı, mən əllə PRIVATECACHE yerləşdirdilər (çünki bizim üçün dünya miqyasında effektiv olub)

34
04 июня '14 в 7:31 2014-06-04 07:31 cavab malkia 04 iyun '14 saat 07:31 2014-06-04 07:31 verilir

Cache_size'yi daha yüksək bir dəyərə artırdığım qədər, hər hansı bir əməliyyat qazanmağı qəbul etmirəm, yəni. PRAGMA cache_size=10000;

22
15 апр. Anefeletos tərəfindən verilmiş cavab 15 aprel 2015-04-15 12:47 '15 at 12:47 2015-04-15 12:47

Bu tutorial oxuduqdan sonra mən bunu proqramda tətbiq etməyə çalışdım.

Ünvanları olan 4-5 fayl var. Hər bir faylda təxminən 30 milyon giriş var. Mən təklif etdiyiniz eyni konfiquradan istifadə edirəm, ancaq INSERT nömrəniz saniyədə azdır (saniyədə ~ 10,000 qeyd).

Burada təklifiniz uğursuz. Səhv / uğursuzluq olmadan bütün qeydlər və bir əlavə üçün bir əməliyyatdan istifadə edirsiniz. Deyək ki, hər bir qeydin bir neçə əlavəyə müxtəlif cədvəllər daxil edilməsini pozmaq. Qeydiyyatın pozulduğu halda nə olur?

ON CONFLICT əmri tətbiq edilmir, çünki bir qeyddə 10 element varsa və element 5 bir CONSTRAINT səhvini alsaydı, bütün əvvəlki 4 əlavələr də girməlidir.

Beləliklə, bir geri dönüş var. Geri qaytarma ilə tək problem bütün əlavələrinizi itirməyiniz və üstdən başlamanızdır. Bunu necə həll edə bilərsən?

Mənim həllim bir çox əməliyyatlardan istifadə etmək idi. Mən bir əməliyyatın hər 10,000 girişini işə başladım və bitirdim (niyə bu nömrəni sınadığım ən sürətli idi). 10.000 ədəd bir sıra yaratdım və orada müvəffəqiyyətli girişləri yerləşdirdim. Bir səhv meydana gəldikdə, geri qayıtdığım, əməliyyata başladım, dizimdən qeydlər qoyduğumda, tökmə və qırılan bir rekorddan sonra yeni bir əməliyyat başladım.

Bu həll mənə pis / dublikat qeydləri olan fayllarla işləyərkən məndə olan problemləri həll etməyə kömək etdi (mənim pis qeydlərimin təxminən 4% -i idi).

Yaratdığım alqoritm mənim prosesimi 2 saat azaltmağa kömək etdi. İndirme işleminin son işlemi, hala yavaş olan 1hr 30m fayldır, lakin ilk olaraq aldığınız 4 saat ile karşılaştırılabilir deyil. Mən 10.000 / s-dən ~ 14.000 / s-ə qədər sürətləndirməyə nail oldum

Kimsə onu necə sürətləndirmək barədə başqa fikirləri varsa, təkliflərimə açıqdır.

ƏLAVƏ OLUNUB :

В дополнение к моему ответу выше, вы должны иметь в виду, что вставки в секунду зависят от жесткого диска, который вы используете. Я тестировал его на трех разных ПК с разными жесткими дисками и получал огромные различия во времени. PC1 (1 час 30 м), PC2 (6 часов) PC3 (14 часов), поэтому я начал задаваться вопросом, почему бы это было так.

После двух недель исследований и проверки нескольких ресурсов: Hard Drive, Ram, Cache, я узнал, что некоторые настройки на вашем жестком диске могут повлиять на скорость ввода-вывода. Нажимая свойства на желаемом выходном диске, вы можете увидеть два варианта на общей вкладке. Opt1: Сжатие этого диска, Opt2: Разрешить файлу этого диска индексировать содержимое.

Отключив эти два варианта, все 3 компьютера теперь занимают примерно одно и то же время для завершения (1 час и от 20 до 40 минут). Если вы сталкиваетесь с медленными вставками, проверьте, настроен ли ваш жесткий диск с этими параметрами. Это сэкономит вам много времени и головных болей, пытаясь найти решение

14
ответ дан Jimmy_A 12 апр. '17 в 19:35 2017-04-12 19:35

Ответ на ваш вопрос заключается в том, что новый sqlite3 имеет улучшенную производительность, используйте это.

Этот ответ Почему SQLAlchemy вставляются с sqlite в 25 раз медленнее, чем с использованием sqlite3 напрямую? автор SqlAlchemy Orm Автор имеет 100k вставки за 0,5 секунды, и я видел аналогичные результаты с python-sqlite и SqlAlchemy. Это заставляет меня поверить, что производительность улучшилась благодаря sqlite3

6
ответ дан doesnt_matter 12 июня '17 в 0:49 2017-06-12 00:49

Существует отличная лекционная форма Paul Betts о том, как он сделал С# akavache так быстро: https://www.youtube.com/watch?v=j7WnQhwBwqA

Может быть, вы найдете для себя какие-то подсказки. Слишком короткое резюме здесь

1
ответ дан Krzysztof Skowronek 21 сент. '17 в 16:28 2017-09-21 16:28

Другие вопросы по меткам или Задайте вопрос