1. 程式人生 > >論execSQL與executeInsert執行效率之差

論execSQL與executeInsert執行效率之差

         看到一遍關於SQLiteDatabase 的execSQL方法和SQLiteStatement的executeInsert的執行效率之比。文中最終得出結論後者比前者效率高,帶著疑惑的心態讓驗證了一把卻得出了截然相反的結論。無論在資料量大小或則是否開啟事務操作上SQLiteDatabase 的execSQL的執行效率還是要比SQLiteStatement的executeInsert高。

以下就是我所做的一個驗證過程

     新建一個數據庫和test表

public class DBhelper extends SQLiteOpenHelper {
	private static final String DATABAS_NAME = "testdb";
	private static final int DATABAS_VERSION = 1;
	public DBhelper(Context context) {
		super(context, DATABAS_NAME, null, DATABAS_VERSION);
	}
	@Override
	public void onCreate(SQLiteDatabase db) {
		StringBuffer sql  =new StringBuffer();
		sql.append("create table test");
		sql.append("(_id int PRIMARY KEY,name varchar,gender int,age int,phoneNumber varchar,address varchar)");	 
        db.execSQL(sql.toString());		
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		
	}
}
使用SQLiteDatabase 的execSQL方法和SQLiteStatement的executeInsert方法進入插入, 比較執行所需要的時間:
public class Dao {
	private DBhelper dbHelper;
	private SQLiteDatabase db;
	private StringBuffer sql_insert;
	private List<Tester> testers;

	public Dao(Context context) {
		this.dbHelper = new DBhelper(context);
		this.db = dbHelper.getWritableDatabase();
		sql_insert = new StringBuffer();
		sql_insert
				.append("INSERT INTO test(name,gender,age,phoneNumber,address) ");
		sql_insert.append(" VALUES( ?, ?, ?, ?, ?)");
		testers = new ArrayList<Tester>();
		// 測試資料
		for (int i = 0; i < 1000; i++) {
			Tester tester = new Tester();
			tester.setId(i);
			tester.setName("name" + i);
			tester.setGender(0);
			tester.setAge(123);
			tester.setPhoneNumber("123456789");
			tester.setAddress("zhejiang ningbo ." + i);

			testers.add(tester);
		}

	}

	/**
	 * 使用SQLiteDatabase 的execSQL方法插入資料
	 */
	public long insertexecSQL() {

		long start = System.currentTimeMillis();

		db.beginTransaction();
		try {
			for (Tester tester : testers) {
				Object[] bindArgs = { tester.getName(), tester.getGender(),
						tester.getAge(), tester.getPhoneNumber(),
						tester.getAddress() };
				db.execSQL(sql_insert.toString(), bindArgs);
			}
			db.setTransactionSuccessful();
		} catch (SQLException e) {
			
		}finally{
			db.endTransaction();
		}

		long end = System.currentTimeMillis();

		return end - start;
	}

	/**
	 * 使用SQLiteStatement的executeInsert方法插入資料
	 */
	public long insertStatement() {
		long start = System.currentTimeMillis();
		db.beginTransaction();
		try {
			for (Tester tester : testers) {
				SQLiteStatement statement = db.compileStatement(sql_insert
						.toString());
				statement.bindString(1, tester.getName());
				statement.bindLong(2, tester.getGender());
				statement.bindLong(3, tester.getAge());
				statement.bindString(4, tester.getPhoneNumber());
				statement.bindString(5, tester.getAddress());
				statement.executeInsert();
			}
			db.setTransactionSuccessful();
		} catch (SQLException e) {
			
		}finally{
			db.endTransaction();
		}
		long end = System.currentTimeMillis();
		return end - start;
	}

}

兩個按鈕,分別呼叫不同的插入方法, 並將執行所需的時間顯示在Button上
public class MainActivity extends Activity {
    private Button btn1;
    private Button btn2;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final Dao dao = new Dao(MainActivity.this);		
		btn1 = (Button) findViewById(R.id.button1);
		btn2 = (Button) findViewById(R.id.button2);
		btn1.setOnClickListener(new OnClickListener() {			
			@Override
			public void onClick(View v) {
				btn1.setText(String.valueOf(dao.insertexecSQL()));				
			}
		});			
	btn2.setOnClickListener(new OnClickListener() {			
			@Override
			public void onClick(View v) {
				btn2.setText(String.valueOf(dao.insertStatement()));			
			}
		});			
	}
}

通過幾次比較發現,在實際實驗後得出的資料是SQLiteStatement的executeInsert並沒有使用SQLiteDatabase 的execSQL方法快,以下為其中一次的秒數截圖,上面按鈕顯示呼叫的方法為SQLiteDatabase 的execSQL,下面按鈕則是SQLiteStatement的executeInsert。



迴圈插入100條資料



迴圈插入1000條資料後




在使用事務迴圈插入1000條資料後



從上面的資料可以看出,隨著資料量的增大,SQLiteDatabase 的execSQL的執行效率遠比SQLiteStatement的executeInsert高,差距非常大。

同時在對其開啟事務後,執行效率也大幅提高,只逼迴圈插入100條資料所需的時間。

db.beginTransaction();
db.setTransactionSuccessful();
db.endTransaction();
以上操做在測試時均未使用非同步類或開啟新執行緒,在插入1000條資料時候,出現非常長的停頓現象,隨著資料量的逐步增加非常容易直接停止響應。

所以建議,在進行大資料操作時候,使用非同步或開啟新執行緒的同時也有必要對其開啟事務。