การแทรก 1000,000 แถวในฐานข้อมูล sqlite3

ฉันต้องการแทรก 10,00,000 แถวลงในฐานข้อมูล แต่การแทรกใช้เวลานานเกินไปเช่น

เช่น. ตอนนี้ฉันกำลังลองใช้แถว 2,055 และใช้เวลา 3 นาทีในการอัปโหลดข้อมูลนี้ลงในฐานข้อมูล .. และครั้งนี้มากเกินไปสำหรับรายการในปี 2055

ต่อไปนี้เป็นวิธีการแทรกข้อมูลลงในฐานข้อมูลของฉัน:

      public void insert_database(Context context,String field1,String field2,String field3,String field4,String field5,String field6 ,String field7,String field8,String field9,String field10)
{

    try
    {
        //RayAllen_Database.beginTransaction();
        RayAllen_Database.execSQL(" insert or replace into "+ TableName_csv+" values( '"+field1+"' ,'"+field2+"','"+field3+"','"+field4+"','"+field5+"','"+field6+"','"+field7+"','"+field8+"','"+field9+"','"+field10+"');");


    }
    catch(Exception e)
    {
        //Log.i("Database Exception", "Exception");
        e.printStackTrace();
    }

}

และในคลาสอื่นที่เรียกว่า: การแยกวิเคราะห์ข้อมูล: ที่นี่ ฉันกำลังแยกวิเคราะห์ไฟล์ csv และในขณะที่แยกวิเคราะห์:

พยายาม {

CSVReader reader=new CSVReader(new FileReader(filename));
String [] nextLine;

//create database
obj.create_database(context);
obj.OpenDatabase(context);
//reader.readNext();

while ((nextLine=reader.readNext())!=null)
{
          //here I am calling the insert_database function
    }
 }

ดังนั้นนี่คือการแยกวิเคราะห์ทีละแถวและเรียกใช้วิธีการแทรกเพื่อแทรกรายการลงในฐานข้อมูล ..

แต่มันใช้เวลานานเกินไป.. ฉันจะปรับปรุงประสิทธิภาพนี้ได้อย่างไร??


person Kanika    schedule 24.05.2012    source แหล่งที่มา
comment
เตรียมคำสั่งหนึ่งครั้งและใช้คำสั่งนั้นสำหรับการแทรกทั้งหมดในเซสชัน ซึ่งจะทำให้เร็วขึ้น developer.android.com/reference/java/sql/PreparedStatement.html   -  person Sarwar Erfan    schedule 24.05.2012
comment
คุณมีเหตุผลที่จะทำการแยกวิเคราะห์ CSV และเติมฐานข้อมูลบนอุปกรณ์หรือไม่? เป็นไปได้ไหมที่จะทำแบบออฟไลน์?   -  person Rajesh    schedule 24.05.2012
comment
แต่ฉันได้รับไฟล์ csv ดังนั้นฉันจึงต้องอ่านทีละแถวเพื่อบันทึกลงในฐานข้อมูล   -  person Kanika    schedule 24.05.2012
comment
@SarwarErfan: คุณช่วยยกตัวอย่างการจัดเตรียมงบให้ฉันหน่อยได้ไหม?   -  person Kanika    schedule 24.05.2012
comment
การแทรก 10 ล้านแถวนั้นมากสำหรับสมาร์ทโฟนธรรมดาๆ ที่จะจัดการ... ไฟล์ CSV ถูกสร้างขึ้นที่ไหน คุณสามารถคัดลอก / สร้างฐานข้อมูล SQLite บนเซิร์ฟเวอร์และส่งฐานข้อมูลที่พร้อมใช้งานแทนได้หรือไม่?   -  person Sam    schedule 24.05.2012
comment
ฉันคิดว่าการแทรกหรือการแทนที่นั้นช้าลงอย่างมาก เพราะในทุกแถวจะต้องตรวจสอบว่ามีบรรทัดอยู่แล้วหรือไม่ สันนิษฐานว่าไม่มีดัชนีใด ๆ   -  person Rafael T    schedule 24.05.2012
comment
@Sam: ฉันได้รับไฟล์ csv ผ่านไฟล์แนบอีเมล จากนั้นฉันก็บันทึกไฟล์นั้นลงใน sdcard จากนั้นฉันก็เริ่มอ่านไฟล์ผ่านโปรแกรมอ่าน csv .. แต่ประเด็นหลักของฉันคือเวลา .. ฉันจะปรับปรุงประสิทธิภาพเช่น: ได้อย่างไร ขณะนี้ในขณะที่อัปโหลดข้อมูล 2,000 ข้อมูลจะใช้เวลาอัปโหลด 3 นาทีและฉันคิดว่ามันมากเกินไป   -  person Kanika    schedule 24.05.2012
comment
หากฐานข้อมูลถูกสร้างขึ้นบนตัวประมวลผลที่เร็วกว่า (หรือชุดตัวประมวลผล) เช่นบนเซิร์ฟเวอร์ หลังจากที่คุณดาวน์โหลดไฟล์แนบอีเมล เวลาในการประมวลผลจะเป็นศูนย์   -  person Sam    schedule 24.05.2012
comment
@RafaelT: ตอนนี้ฉันใช้แค่ส่วนแทรกเท่านั้น แต่ยังใช้เวลา 3 นาทีในการอัปโหลดไฟล์นี้จำนวน 2,055 รายการ???   -  person Kanika    schedule 24.05.2012
comment
@Kanika: โปรดไปที่พีซีที่คุณมีอินเทอร์เน็ตแล้วลองลิงค์นี้ (ถ้าคุณมีอินเทอร์เน็ต คุณอาจจะลองใช้ Google ก่อน) google .com/#q=android+prepared+statement+insert+example   -  person Sarwar Erfan    schedule 24.05.2012
comment
FFS: เริ่มใช้ธุรกรรมและจัดกลุ่มส่วนแทรกของคุณเป็นส่วนที่เหมาะสม เช่น › 1,000 แทรกป๊อป มันเร็วขึ้นมาก สร้างคำสั่งที่เตรียมไว้และนำมาใช้ใหม่   -  person Jens    schedule 24.05.2012


คำตอบ (3)


ตัวอย่างสั้นๆ ว่าทำไมคุณควรทำสิ่งที่ถูกต้องแทนที่จะเป็น "ผิด" สิ่งนี้ได้รับการทดสอบการทำงานบน ICS 4.0.4 ซึ่งมีประสิทธิภาพ INSERT แย่มาก

ขั้นแรก SQLiteOpenHelper แบบธรรมดาที่สร้างตารางที่มีข้อจำกัด UNIQUE ในคอลัมน์เพื่อทำให้เกิดความขัดแย้งเป็นครั้งคราว

class SimpleHelper extends SQLiteOpenHelper {
    // InsertHelpers are a really good idea - they format a prepared statement
    // for you automatically.
    InsertHelper mInsert;
    public SimpleHelper(Context context) {
        super(context, "tanika.db", null, 1);
    }
    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
        mInsert = new InsertHelper(db, "target");
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE target (\n" +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n" +
                "val1 TEXT NOT NULL,\n" +
                "val2 TEXT NOT NULL,\n" +
                "val3 TEXT NOT NULL,\n" +
                // Let's make one unique so we can get some juicy conflicts
                "val4 TEXT NOT NULL UNIQUE\n" +
                ")");
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

เมื่อรวมไว้ใน Activity เก่าใดๆ เราเพิ่มวิธีทดสอบง่ายๆ ต่อไปนี้:

long test(final int n) {
    long started = System.currentTimeMillis();
    ContentValues values = new ContentValues();

    for (int i = 0; i < n; i++) {
        values.clear();
        // Every 20th insert, generate a conflict in val4
        String val4 = String.valueOf(started + i);
        if (i % 20 == 0) {
            val4 = "conflict";
        }
        values.put("val1", "Value1");
        values.put("val2", "Value2");
        values.put("val3", "Value3");
        values.put("val4", val4);
        mHelper.mInsert.replace(values);
    }
    return System.currentTimeMillis() - started;
}

อย่างที่คุณเห็น สิ่งนี้จะทำให้เกิดข้อขัดแย้งทุกๆ 20 INSERT หรือประมาณนั้น การเรียก InsertHelper#replace(..) ทำให้ผู้ช่วยเหลือใช้ INSERT OR REPLACE กับข้อขัดแย้ง

ตอนนี้ เรามารันโค้ดทดสอบนี้โดยมีและไม่มีธุรกรรมล้อมรอบ

class Test1 extends AsyncTask<Integer, Void, Long> {
    @Override
    protected Long doInBackground(Integer... params) {
        return test(params[0]);
    }
    @Override
    protected void onPostExecute(Long result) {
        System.out.println(getClass().getSimpleName() + " finished in " + result + "ms");
    }
}

class Test2 extends AsyncTask<Integer, Void, Long> {
    protected Long doInBackground(Integer... params) {
        SQLiteDatabase db = mHelper.getWritableDatabase();
        db.beginTransaction();
        long started = System.currentTimeMillis();
        try {
            test(params[0]);
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();
        }
        return System.currentTimeMillis() - started;
    }
    @Override
    protected void onPostExecute(Long result) {
        System.out.println(getClass().getSimpleName() + " finished in " + result + "ms");
    }
}

ทุกอย่างเริ่มต้นเช่นนี้:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    mHelper = new SimpleHelper(this);
    mHelper.getWritableDatabase(); // Forces the helper to initialize.
    new Test1().execute(2055);
    new Test2().execute(2055);
}

แล้วผลลัพธ์ล่ะ? หากไม่มีธุรกรรม INSERTs จะใช้เวลา 41072ms ด้วยการทำธุรกรรมจะใช้เวลา 940ms กล่าวโดยย่อ FFS เริ่มใช้ InsertHelpers และธุรกรรม

person Jens    schedule 24.05.2012
comment
InsertHelper เลิกใช้แล้ว มีวิธีอื่นใดในการแทรก db ที่เร็วขึ้นใน Android - person YLS; 27.03.2017

คุณสามารถเติมฐานข้อมูลของคุณโดยใช้เครื่องมือออฟไลน์ จากนั้นนำเข้าฐานข้อมูลเมื่อคุณติดตั้งแพ็คเกจของคุณ คุณสามารถจัดเก็บฐานข้อมูลในการ์ด SD ภายนอกหรือในโฟลเดอร์เนื้อหาของแอปพลิเคชันของคุณ

นี่คือวิธีที่ฉันทำ:

  1. คัดลอกฐานข้อมูลแอปพลิเคชันไปยังโฟลเดอร์ในเครื่องโดยใช้ Android Debuger Bridge (adb) ดังนี้: adb pull /data/data/<your application provider>/databases/yourdatbase.db C:/users/databases/yourdatbase.db

  2. เชื่อมต่อกับฐานข้อมูล SQLites C:/users/databases/yourdatbase.db ด้วยเครื่องมือ GUI/CLI ที่คุณชื่นชอบ และเติมเต็มจำนวนบันทึก 1,000,000 รายการของคุณให้สมบูรณ์

  3. คัดลอกฐานข้อมูลที่มีประชากรของคุณไปยังโฟลเดอร์ asset สภาพแวดล้อมการพัฒนา Android ของคุณ

  4. ตอนนี้ถอนการติดตั้งแอปพลิเคชันของคุณออกจากอุปกรณ์เพื่อให้แน่ใจว่าไม่มีการสร้างฐานข้อมูลเมื่อคุณติดตั้งเป็นครั้งแรก

  5. แก้ไขคลาส SQLiteHepler ของคุณเพื่อตรวจสอบว่ามีฐานข้อมูลอยู่หรือไม่ และถ้ามีอยู่ก็จะใช้ฐานข้อมูลนั้น หากไม่มีฐานข้อมูลอยู่แล้ว Helper จะคัดลอกฐานข้อมูลจากโฟลเดอร์สินทรัพย์ของคุณพร้อมกับบันทึก 1 000 000 ของคุณ นี่คือวิธีที่ฉันทำ:

    public class MyDatabaseHelper extends SQLiteOpenHelper {
    
        /*
            Other SQLiteOpenHelper declarations here ...
        */
    
        private static final String DATABASE_NAME   = "application.db";
        private static final String DB_PATH         = "/data/data/" + context.getPackageName() + "/databases/";
    
    
        /*
            Your SQLiteOpenHelper functions/procedures here ...
        */
    
        public boolean isDataBaseExist() {
    
            File dbFile     = new File(DB_PATH + DATABASE_NAME);
            return dbFile.exists();
        }
    
        public void copyDataBase(Context context) throws IOException {
    
            this.getReadableDatabase();
    
            InputStream inFile      = context.getResources().getAssets().open(DATABASE_NAME);
    
            // Path to the just created empty db
            String outFileName      = DB_PATH + DATABASE_NAME;
            OutputStream outFile    = new FileOutputStream(outFileName);
    
            // transfer bytes from the inputfile to the outputfile
            byte[] buffer = new byte[1024];
    
            int length;
    
            while ((length = inFile.read(buffer)) > 0) {
    
                outFile.write(buffer, 0, length);
    
            }
    
            // Close the streams
            outFile.flush();
            outFile.close();
            inFile.close();
        } 
    

ฐานข้อมูลนี้จะสอดคล้องกับแอปของคุณ และเมื่อเปิดตัวครั้งแรก ข้อมูลทั้งหมดจะอยู่ที่นั่น อาจมีวิธีที่ง่ายกว่านี้ แต่ฉันหวังว่านี่จะช่วยใครซักคนได้

person Lukuluba    schedule 24.05.2012

การเร่งความเร็วการดำเนินการแทรก sqlite จะต้องผ่าน กรณีที่คล้ายกันและแสดงวิธีใช้ธุรกรรมเพื่อเพิ่มประสิทธิภาพการแทรก

person andyandy    schedule 24.05.2012