2010-01-23 13 views
17

मेरे पास मोबाइल एप्लिकेशन है। मेरे ग्राहक के पास एक बड़ा डेटा सेट ~ 100,000 रिकॉर्ड है। यह अक्सर अद्यतन किया जाता है। जब हम सिंक करते हैं तो हमें एक डेटाबेस से दूसरे डेटाबेस में कॉपी करने की आवश्यकता होती है।एक डेटाबेस से दूसरे डेटाबेस में 100 000 रिकॉर्ड डालने का सबसे तेज़ तरीका क्या है?

मैंने दूसरे डेटाबेस को मुख्य से जोड़ा है, और insert into table select * from sync.table चलाएं।

यह बेहद धीमा है, मुझे लगता है कि इसमें लगभग 10 मिनट लगते हैं। मैंने देखा कि जर्नल फ़ाइल चरण-दर-चरण बढ़ जाती है।

मैं इसे कैसे गति दे सकता हूं?

मैं अनुक्रमित बंद है संपादित, और मैं पत्रिका बंद है।

insert into table select * from sync.table 

का उपयोग करते हुए यह अभी भी 10 मिनट लगते हैं।

संपादित 2

अगर मैं की तरह

select id,invitem,invid,cost from inventory where itemtype = 1 
order by invitem limit 50 

यह 15-20 सेकंड लेता है एक प्रश्न चलाते हैं।

तालिका स्कीमा है:

CREATE TABLE inventory 
('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
'serverid' INTEGER NOT NULL DEFAULT 0, 
'itemtype' INTEGER NOT NULL DEFAULT 0, 
'invitem' VARCHAR, 
'instock' FLOAT NOT NULL DEFAULT 0, 
'cost' FLOAT NOT NULL DEFAULT 0, 
'invid' VARCHAR, 
'categoryid' INTEGER DEFAULT 0, 
'pdacategoryid' INTEGER DEFAULT 0, 
'notes' VARCHAR, 
'threshold' INTEGER NOT NULL DEFAULT 0, 
'ordered' INTEGER NOT NULL DEFAULT 0, 
'supplier' VARCHAR, 
'markup' FLOAT NOT NULL DEFAULT 0, 
'taxfree' INTEGER NOT NULL DEFAULT 0, 
'dirty' INTEGER NOT NULL DEFAULT 1, 
'username' VARCHAR, 
'version' INTEGER NOT NULL DEFAULT 15 
) 

इंडेक्स में ... का चयन

CREATE INDEX idx_inventory_categoryid ON inventory (pdacategoryid); 
CREATE INDEX idx_inventory_invitem ON inventory (invitem); 
CREATE INDEX idx_inventory_itemtype ON inventory (itemtype); 

मैं सोच रहा हूँ, डालने की तरह बनाई गई हैं * करने के लिए सबसे तेजी से निर्मित तरीका नहीं है से भारी डेटा कॉपी करें?

संपादित 3

SQLite सर्वर-कम है, इसलिए, एक विशेष जवाब मतदान रोक कृपया क्योंकि है कि इसका जवाब मुझे यकीन नहीं है।

+0

आपके मौजूदा प्रश्न की निरंतरता की तरह लगता है ?? http://stackoverflow.com/questions/2121336/insert-takes-too-long-code-optimization-needed – AdaTheDev

+0

यह है, मुझे नहीं पता कि मैं अपने धागे के लिए कैसे उत्तर दे सकता हूं, मैं केवल पोस्ट पर टिप्पणी कर सकता हूं, या इसका उत्तर दो .... लेकिन मैं एक और सवाल उठाना चाहता हूं ... – Pentium10

+0

प्रत्येक पंक्ति कैसी दिखती है? 100,000 रिकॉर्ड बहुत अधिक पंक्तियां छोटी नहीं हैं। हम नियमित रूप से 300,000 रिकॉर्ड के साथ डेटा आयात चलाते हैं और यह कुछ सेकंड में चलता है (जिसे हम धीमे मानते हैं)। –

उत्तर

6

मैं नहीं लगता कि दो डेटाबेस संलग्न और INSERT INTO foo (SELECT * FROM bar) चल रहा यह करने के लिए सबसे तेज़ तरीका है। यदि आप हैंडहेल्ड डिवाइस और सर्वर (या कोई अन्य डिवाइस) के बीच सिंक कर रहे हैं तो परिवहन तंत्र बाधा बन सकता है? या पहले से ही एक ही फाइलिसम पर दो डेटाबेस फाइलें हैं? यदि डिवाइस पर फाइल सिस्टम धीमी फ्लैश-मेमोरी है, तो क्या यह एक बाधा हो सकती है?

क्या आप अपने डिवाइस पर कच्चे SQLite C कोड को संकलित/चलाने में सक्षम हैं? (मुझे लगता है कि रॉ sqlite3 समामेलन WinCE/मोबाइल के लिए संकलन चाहिए) यदि हां, तो और आप तैयार हैं:

  • कुछ सी कोड (SQLite सी एपीआई का उपयोग) द्वारा डेटा हानि की
  • बढ़ाएँ जोखिम लिखने के लिए डिस्क जर्नलिंग

दो डेटाबेसों के बीच 100K रिकॉर्ड्स को कॉपी/सिंक्रनाइज़ करने के लिए एक छोटे से स्टैंड-अलोन निष्पादन योग्य लिखना संभव होना चाहिए।

मैं से कुछ पोस्ट किया है कि यहाँ क्या मैं SQLite के अनुकूलन के बारे में सीखा सम्मिलित करता है: Improve INSERT-per-second performance of SQLite?


संपादित करें:वास्तविक कोड के साथ इस बाहर की कोशिश की ...

मुझे नहीं पता विंडोज मोबाइल निष्पादन योग्य बनाने में शामिल सभी कदमों को जानें, लेकिन SQLite3 amalgamation को विजुअल स्टूडियो का उपयोग करके बॉक्स के बाहर संकलित करना चाहिए। यहां एक नमूना main.c कार्यक्रम दो SQLite डेटाबेस खुलती (दोनों एक ही स्कीमा करना होगा - #define TABLE बयान देखें) है और एक SELECT कथन निष्पादित करता है और फिर एक सम्मिलित कथन के परिणामस्वरूप पंक्तियों बांधता:

/************************************************************* 
** The author disclaims copyright to this source code. In place of 
** a legal notice, here is a blessing: 
** 
** May you do good and not evil. 
** May you find forgiveness for yourself and forgive others. 
** May you share freely, never taking more than you give. 
**************************************************************/ 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include <string.h> 
#include "sqlite3.h" 

#define SOURCEDB "C:\\source.sqlite" 
#define DESTDB "c:\\dest.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 * sourceDB; 
    sqlite3 * destDB; 

    sqlite3_stmt * insertStmt; 
    sqlite3_stmt * selectStmt; 

    char * insertTail = 0; 
    char * selectTail = 0; 

    int n = 0; 
    int result = 0; 
    char * sErrMsg = 0; 
    clock_t cStartClock; 

    char sInsertSQL [BUFFER_SIZE] = "\0"; 
    char sSelectSQL [BUFFER_SIZE] = "\0"; 

    /* Open the Source and Destination databases */ 
    sqlite3_open(SOURCEDB, &sourceDB); 
    sqlite3_open(DESTDB, &destDB); 

    /* Risky - but improves performance */ 
    sqlite3_exec(destDB, "PRAGMA synchronous = OFF", NULL, NULL, &sErrMsg); 
    sqlite3_exec(destDB, "PRAGMA journal_mode = MEMORY", NULL, NULL, &sErrMsg); 

    cStartClock = clock(); /* Keep track of how long this took*/ 

    /* Prepared statements are much faster */ 
    /* Compile the Insert statement */ 
    sprintf(sInsertSQL, "INSERT INTO TTC VALUES (NULL, @RT, @BR, @VR, @ST, @VI, @DT, @TM)"); 
    sqlite3_prepare_v2(destDB, sInsertSQL, BUFFER_SIZE, &insertStmt, &insertTail); 

    /* Compile the Select statement */ 
    sprintf(sSelectSQL, "SELECT * FROM TTC LIMIT 100000"); 
    sqlite3_prepare_v2(sourceDB, sSelectSQL, BUFFER_SIZE, &selectStmt, &selectTail); 

    /* Transaction on the destination database */ 
    sqlite3_exec(destDB, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg); 

    /* Execute the Select Statement. Step through the returned rows and bind 
    each value to the prepared insert statement. Obviously this is much simpler 
    if the columns in the select statement are in the same order as the columns 
    in the insert statement */ 
    result = sqlite3_step(selectStmt); 
    while (result == SQLITE_ROW) 
    { 

     sqlite3_bind_text(insertStmt, 1, sqlite3_column_text(selectStmt, 1), -1, SQLITE_TRANSIENT); /* Get Route */ 
     sqlite3_bind_text(insertStmt, 2, sqlite3_column_text(selectStmt, 2), -1, SQLITE_TRANSIENT); /* Get Branch */ 
     sqlite3_bind_text(insertStmt, 3, sqlite3_column_text(selectStmt, 3), -1, SQLITE_TRANSIENT); /* Get Version */ 
     sqlite3_bind_text(insertStmt, 4, sqlite3_column_text(selectStmt, 4), -1, SQLITE_TRANSIENT); /* Get Stop Number */ 
     sqlite3_bind_text(insertStmt, 5, sqlite3_column_text(selectStmt, 5), -1, SQLITE_TRANSIENT); /* Get Vehicle */ 
     sqlite3_bind_text(insertStmt, 6, sqlite3_column_text(selectStmt, 6), -1, SQLITE_TRANSIENT); /* Get Date */ 
     sqlite3_bind_text(insertStmt, 7, sqlite3_column_text(selectStmt, 7), -1, SQLITE_TRANSIENT); /* Get Time */ 

     sqlite3_step(insertStmt);  /* Execute the SQL Insert Statement (Destination Database)*/ 
     sqlite3_clear_bindings(insertStmt); /* Clear bindings */ 
     sqlite3_reset(insertStmt);  /* Reset VDBE */ 

     n++; 

     /* Fetch next from from source database */ 
     result = sqlite3_step(selectStmt); 

    } 

    sqlite3_exec(destDB, "END TRANSACTION", NULL, NULL, &sErrMsg); 

    printf("Transfered %d records in %4.2f seconds\n", n, (clock() - cStartClock)/(double)CLOCKS_PER_SEC); 

    sqlite3_finalize(selectStmt); 
    sqlite3_finalize(insertStmt); 

    /* Close both databases */ 
    sqlite3_close(destDB); 
    sqlite3_close(sourceDB); 

    return 0; 
} 

पर मेरी विंडोज डेस्कटॉप मशीन यह कोड 1.20 सेकंड में source.sqlite से dest.sqlite से 100k रिकॉर्ड कॉपी करता है। मुझे नहीं पता कि फ्लैश मेमोरी के साथ मोबाइल डिवाइस पर आप किस प्रकार का प्रदर्शन देखेंगे (लेकिन मैं उत्सुक हूं)।

+0

दो डेटाबेस पहले से ही एक ही फाइल सिस्टम पर हैं। फाइल सिस्टम एक धीमी फ्लैश-मेमोरी है और यह एक बाधा हो सकती है। मुझे नहीं पता कि मेरे डिवाइस पर कच्चे SQLite C कोड को संकलित/चलाने के लिए कैसे। यदि आप मुझे सही दिशा में इंगित करते हैं तो मैं कोशिश करूंगा। – Pentium10

+0

यदि आप विंडोज मोबाइल सी ++ निष्पादन योग्य बनाने के लिए विजुअल स्टूडियो का उपयोग कर सकते हैं तो यह सरल होना चाहिए। SQLite3 Amalgamation में सभी SQLite कोड एक '.c' फ़ाइल और एक' .h' फ़ाइल में शामिल हैं। –

0

केवल डेल्टा भेजें। अर्थात। केवल diffs भेजें। अर्थात। केवल क्या बदल गया है भेजें।

+0

प्रत्येक पंक्ति में कम से कम 1 संशोधित कॉलम होगा, मुझे नहीं पता कि कौन सा है। यह पता लगाने में दर्द होगा, और उन पंक्तियों पर एक अद्यतन चलाएं। रीफ्रेश ऑपरेशन जैसे मेरे प्रश्न के बारे में सोचें। – Pentium10

10

यदि लक्ष्य एमएस एसक्यूएल सर्वर का कुछ संस्करण है, SqlBulkCopy बड़े डेटा सेट के लिए एक कुशल डालने प्रदान करता है यह bcp कमांड के समान है।

आप डालने से पहले गैर-क्लस्टर इंडेक्स को अक्षम/हटा भी सकते हैं, और बाद में उन्हें फिर से बना सकते हैं।

SQLite में, इन आमतौर पर बहुत तेजी से कर रहे हैं:

.dump ?TABLE? ...  Dump the database in an SQL text format 
.import FILE TABLE  Import data from FILE into TABLE 

भी आज़माएं: PRAGMA journal_mode = OFF

FYI करें, आप विंडोज मोबाइल पर कमांड लाइन उपयोगिता को चलाने के लिए यदि आप इसे अपने पैकेज में शामिल हैं सक्षम होना चाहिए ।

+1

टैग में कहा गया है, यह sqlite है। मैं पहले से ही दो डेटाबेस को जोड़कर और एक इंसर्ट का उपयोग करके SQLite की थोक प्रति का उपयोग कर रहा हूं .. डेटा कॉपी करने के लिए * विधि से चुनें। मेरी अनुक्रमणिका, ट्रिगर्स और कई pragmas पहले ही बंद कर दिया गया है। – Pentium10

+2

एसक्लाइट के लिए '.dump/.import' आदेशों को चुनने के बजाय' (डीडीएस दोनों निर्दिष्ट नहीं किया गया था) – jspcal

+0

मुझे यकीन नहीं है कि मोबाइल पर मैं '.dump/.import' आदेश चला सकता हूं। यह सर्वर कम है। (जैसा कि उल्लेख नहीं है कि दोनों डीबीएस स्क्लाइट हैं, मुझे याद आया। लेकिन आप यह जानकर कटौती कर सकते हैं कि आप एसक्यूएल में विभिन्न प्रकार के डीबी को नहीं जोड़ सकते हैं) – Pentium10

1

संलग्न डेटाबेस में शामिल * एसक्यूएलसाइट में सबसे तेज़ उपलब्ध विकल्प है। कुछ चीजों को देखने के लिए।

  1. लेनदेन। सुनिश्चित करें कि पूरी चीज एक लेनदेन के अंदर है। यह वास्तव में महत्वपूर्ण है। यदि यह केवल एक एसक्यूएल कथन है तो यह महत्वपूर्ण नहीं है, लेकिन आपने कहा कि जर्नल "चरण-दर-चरण" बढ़ाता है जो इंगित करता है कि यह एक से अधिक कथन है।

  2. ट्रिगर्स। क्या आपके पास ट्रिगर चल रहे हैं? वे स्पष्ट रूप से प्रदर्शन को प्रभावित कर सकते हैं।

  3. बाधाएं। क्या आपके पास अनावश्यक बाधाएं हैं? आप उन्हें अक्षम नहीं कर सकते हैं या उन्हें फिर से जोड़ सकते हैं, इसलिए यदि वे आवश्यक हैं तो आप उनके बारे में ज्यादा कुछ नहीं कर सकते हैं, लेकिन यह विचार करने के लिए कुछ है।

आपने पहले ही इंडेक्स को बंद करने का उल्लेख किया है।

+0

ने यह भी बताया कि मेरे पास जर्नल मोड बंद है, इसका मतलब है कि लेन-देन बंद हैं, लेनदेन फ़ाइल को डिस्क पर लिखने में काफी समय लगता है, इससे मदद नहीं मिलती है ... बंद कर दिया गया है। मुझे बाधाएं नहीं हैं और न ही डालने के लिए ट्रिगर्स हैं। – Pentium10

0

sync.table डेटाबेस तालिका को एक अलग फ़ाइल में संग्रहीत करने के बारे में क्या? सिंक करने के लिए आपको बस उस फ़ाइल की एक प्रति बनाने की आवश्यकता है। मैं शर्त लगाता हूं कि SQL द्वारा समन्वयित करने से तेज़ तरीका है।

+0

मुझे आपके विचार को समझ में नहीं आता है। वहाँ दो फाइलें पहले से ही maindb.sqlite और sync.sqlite को अलग कर चुकी हैं। SQLite में प्रत्येक तालिका के लिए कोई अलग फ़ाइल नहीं है। एक फ़ाइल एक डेटाबेस है। – Pentium10

+0

मुझे लगता है कि maindb.sqlite में टेबल का एक गुच्छा है और आप बस उन तालिकाओं में से एक को एक दिशा (= बैकअप?) में सिंक करना चाहते हैं। यदि ऐसा है, तो आप एक नई डेटाबेस फ़ाइल (उदाहरण के लिए maindb-syncable.sqlite) पेश कर सकते हैं जिसमें केवल उस तालिका को शामिल किया गया है जिसे आपको सिंक्रनाइज़ करने की आवश्यकता है। फिर जब भी आपको सिंक करने की आवश्यकता हो, उस फ़ाइल की एक प्रति बनाएं। –

+0

यह एक पूर्ण सिंक प्रक्रिया है। एक मुख्य केंद्रीय डेटाबेस है और उत्पाद में डेस्कटॉप संस्करण भी है। एक सिंक प्रक्रिया है जब केंद्रीय डेटाबेस से डेटा मोबाइल डिवाइस पर सिंक किया जाता है। ग्राहक एक बड़ी सूची के साथ बोर्ड पर आने के बाद समस्या दिखाई दी। इसलिए न केवल सूची तालिका बड़ी है, लेकिन जल्द या बाद में चालान, व्यय, भागों की मेज बड़ी भी हो सकती है। मैं ** सभी रिकॉर्ड्स ** सिंक से (सर्वर से नया परिणाम) -> मुख्य (मोबाइल स्थानीय) में डालने या प्रतिस्थापित करना चाहता हूं। Sync.sqlite डीबी सिंक प्रक्रिया द्वारा डाउनलोड किया जाता है। – Pentium10

1

क्या सभी 100 000 रिकॉर्ड अक्सर बदलते हैं? या यह एक सबसेट है जो बदलता है?

यदि ऐसा है, तो आपको एक अद्यतन_since_last_sync कॉलम जोड़ने पर विचार करना चाहिए जो अद्यतन होने पर ध्वजांकित हो जाता है, इसलिए अगली सिंक के दौरान आप केवल उन रिकॉर्ड्स की प्रतिलिपि बनाते हैं जो वास्तव में बदल गए हैं। एक बार रिकॉर्ड्स की प्रतिलिपि बना लेने के बाद, आप ध्वज कॉलम को शून्य पर सेट कर देते हैं।

+0

मेरे पास पहले से ही यह बनाया गया है। 100,000 रिकॉर्ड ब्रांड नए हैं। – Pentium10

4

मैं अभी मोबाइल हूँ तो मैं एक बहुत विस्तृत उत्तर पोस्ट नहीं कर सकते हैं, लेकिन इस लायक पढ़ने हो सकता है:

http://sqlite.org/cvstrac/wiki?p=SpeedComparison

आप देख सकते हैं SQLite 3 रास्ता तेजी से जब अनुक्रमणिका का उपयोग कर आवेषण प्रदर्शन और/या लेनदेन। साथ ही, चयनों से INSERTs SQLite का मजबूत प्रतीत नहीं होता है।

+0

तो आप एक चयन कर रहे हैं, फिर तैयार डालने के बयान बनाने और सम्मिलित कथन निष्पादित करने के लिए इसके माध्यम से चल रहे हैं यह सब बताए गए से INSERTs से तेज़ है? – Pentium10

0

यदि आपके पास पहले से ही आपको लेनदेन में इसे लपेटने की आवश्यकता नहीं है। एक महत्वपूर्ण गति अंतर बनाता है।

+0

तालिका 1 में सम्मिलित करें ... तालिका 2 से चुनें * एक प्रश्न है इसलिए यह लेनदेन में है – Pentium10

संबंधित मुद्दे