精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

在SQLite中插入10億條Python VS Rust

開發 后端
寫腳本來進行數據處理,比如說給數據庫導入導出數據,這種任務一般來說最方便的方法是用python腳本,但是如果數據量比較大時候(比如上億條)時候Python就會超級慢,看到無法忍受。

在實際生活中,市場有這樣的案例:寫腳本來進行數據處理,比如說給數據庫導入導出數據,這種任務一般來說最方便的方法是用python腳本,但是如果數據量比較大時候(比如上億條)時候Python就會超級慢,看到無法忍受。在這種案例時候該怎么做呢,有一個外國老哥分享了自己的實踐經歷,并且對比了Python和Rust語言給SQLite插入十一條數據的情況,最后用Rust實現了在一分鐘來完成任務。我們在此分享一下該實踐過程,希望能對大家有所啟迪,大家也可以嘗試自己最拿手方法來實現該例子,并對比一下具體性能。

概述

案例中的任務是SQLite數據庫插入10億條的數據。表(user)數據結構和約束如下:

  1. create table IF NOT EXISTS user 
  2. id INTEGER not null primary key, 
  3. area CHAR(6), 
  4. age INTEGER not null, 
  5. active INTEGER not null 
  6. ); 

隨機生成數據。其中are列為六位數的區號(任何六位數字)。age將是5、10 或15中的一個數字。Active為0或1。

  • 實驗環境硬件配置為:MacBook Pro,2019(2.4 GHz 四核i5,8GB內存,256GB SSD硬盤,Big Sur 11.1)。
  • 任務前提:任務無需保持程序穩健性,如果進程崩潰并且所有數據都丟失了也沒關系。可以再次運行腳本。
  • 需要充分利用我的機器資源:100% CPU、8GB 內存和千兆字節的SSD空間。

無需使用真正的隨機方法,stdlib偽隨機方法即可。

Python

首先是原始版本的Python方法。Python標準庫提供了一個SQLite模塊,首先使用它編寫了第一個版本。代碼如下:

  1. import sqlite3 
  2. from commons import get_random_age, get_random_active, get_random_bool, get_random_area_code, create_table 
  3. DB_NAME = "naive.db" 
  4. def faker(con: sqlite3.Connection, count=100_000): 
  5. for _ in range(count): 
  6. age = get_random_age() 
  7. active = get_random_active() 
  8. # switch for area code 
  9. if get_random_bool(): 
  10. # random 6 digit number 
  11. area = get_random_area_code() 
  12. con.execute('INSERT INTO user VALUES (NULL,?,?,?)', (area, age, active)) 
  13. else: 
  14. con.execute('INSERT INTO user VALUES (NULL,NULL,?,?)', (age, active)) 
  15. con.commit() 
  16. def main(): 
  17. con = sqlite3.connect(DB_NAME, isolation_level=None
  18. con.execute('PRAGMA journal_mode = WAL;') 
  19. create_table(con) 
  20. faker(con, count=10_000_000
  21. if __name__ == '__main__': 
  22. main() 

在該腳本中,通for循環中一一插入1000萬條數據。執行花了將近15分鐘。基于此進行優化迭代,提高性能。

SQLite中,每次插入都是原子性的并且為一個事務。每個事務都需要保證寫入磁盤(涉及IO操作),因此可能會很慢。為了優化,可以嘗試通過不同大小的批量插入,對比發現,100000是最佳選擇。通過這個簡單的更改,運行時間減少到了10分鐘,優化了3分之一,但是仍然非常耗時。優化后,批量插入版本源碼:

SQLite庫優化

除了在代碼層優化外,如果對于單純的數據寫入,對數據庫本身搞的優化也是非常重要的。對于SQLite優化,可以做如下配置:

  1. PRAGMA journal_mode = OFF
  2. PRAGMA synchronous = 0
  3. PRAGMA cache_size = 1000000
  4. PRAGMA locking_mode = EXCLUSIVE
  5. PRAGMA temp_store = MEMORY

具體解釋:

首先,journal_mode設置為OFF,將會關閉回滾日志,禁用 SQLite 的原子提交和回滾功能,這樣在事務失敗情況下,無法恢復,基于例子實例穩健性要求可以設置,但是嚴禁在生產環境中使用。

其次,關閉synchronous,SQLite可以不再校驗磁盤寫入的數據可靠性。寫入SQLite可能并不意味著它已刷新到磁盤。同樣,嚴禁在生產環境中啟用。

cache_size用戶指定SQLite允許在內存中保留多少內存頁。不要在生產中分配太高的的數值。

使用在EXCLUSIVE鎖定模式,SQLite連接持有的鎖永遠不會被釋放。

設置temp_store到MEMOR將使其表現得像一個內存數據庫。

優化性能

對上面的兩個腳本,添加 SQLite優化參數,然后重新運行:

  1. def main():     
  2. con = sqlite3.connect(DB_NAME, isolation_level=None)     
  3. con.execute('PRAGMA journal_mode = OFF;')     
  4. con.execute('PRAGMA synchronous = 0;')     
  5. con.execute('PRAGMA cache_size = 1000000;') # give it a GB     
  6. con.execute('PRAGMA locking_mode = EXCLUSIVE;')     
  7. con.execute('PRAGMA temp_store = MEMORY;')     
  8. create_table(con)     

faker(con, count=100_000_000)

優化后版本,原始版本,插入1億行數據,大概花了10分鐘;對比批量插入版本大概花了8.5分鐘。

pypy版本

對比CPython PyPy在數據處理中可以提高性能,據說可以提高4倍以上的性能。本實驗中也嘗試編譯PyPy解釋器,運行腳本(代碼無需修改)。

使用pypy解釋器,批處理版本,插入1億行數據只需2.5分鐘。性能大概是Cpython的3.5倍,可見傳說的4倍性能提高確實是真的,誠不我欺也!。同時,為了測試在純循環插入中消耗的時間,在腳本中刪除SQL指令并運行:

以上腳本在CPython中耗時5.5分鐘 。PyPy執行耗時1.5分鐘(同樣提高了3.5倍)。

Rust

在完成Python各種優化折騰。又嘗試了Rust版本的插入,對比也有個原始版本和批量插入版本。原始版本,也是每行插入:

  1. use rusqlite::{params, Connection}; 
  2. mod common; 
  3. fn faker(mut conn: Connection, count: i64) { 
  4. let tx = conn.transaction().unwrap(); 
  5. for _ in 0..count { 
  6. let with_area = common::get_random_bool(); 
  7. let age = common::get_random_age(); 
  8. let is_active = common::get_random_active(); 
  9. if with_area { 
  10. let area_code = common::get_random_area_code(); 
  11. tx.execute( 
  12. "INSERT INTO user VALUES (NULL, ?, ?, ?)", 
  13. params![area_code, age, is_active], 
  14. .unwrap(); 
  15. } else { 
  16. tx.execute( 
  17. "INSERT INTO user VALUES (NULL, NULL, ?, ?)", 
  18. params![age, is_active], 
  19. .unwrap(); 
  20. tx.commit().unwrap(); 
  21. fn main() { 
  22. let conn = Connection::open("basic.db").unwrap(); 
  23. conn.execute_batch( 
  24. "PRAGMA journal_mode = OFF
  25. PRAGMA synchronous = 0
  26. PRAGMA cache_size = 1000000
  27. PRAGMA locking_mode = EXCLUSIVE
  28. PRAGMA temp_store = MEMORY;", 
  29. .expect("PRAGMA"); 
  30. conn.execute( 
  31. "CREATE TABLE IF NOT EXISTS user ( 
  32. id INTEGER not null primary key, 
  33. area CHAR(6), 
  34. age INTEGER not null, 
  35. active INTEGER not null)", 
  36. [], 
  37. .unwrap(); 
  38. faker(conn, 100_000_000) 

該版執行,大概用時3分鐘。然后我做了進一步的實驗:

將rusqlite,換成sqlx異步運行。

  1. use std::str::FromStr;     
  2.  
  3. use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqliteSynchronous};     
  4. use sqlx::{ConnectOptions, Connection, Executor, SqliteConnection, Statement};     
  5.  
  6. mod common;     
  7.  
  8. async fn faker(mut conn: SqliteConnection, count: i64) -> Result<(), sqlx::Error> {     
  9. let mut tx = conn.begin().await?;     
  10. let stmt_with_area = tx     
  11. .prepare("INSERT INTO user VALUES (NULL, ?, ?, ?)")     
  12. .await?;     
  13. let stmt = tx     
  14. .prepare("INSERT INTO user VALUES (NULL, NULL, ?, ?)")     
  15. .await?;     
  16. for _ in 0..count {     
  17. let with_area = common::get_random_bool();     
  18. let age = common::get_random_age();     
  19. let is_active = common::get_random_active();     
  20. if with_area {     
  21. let area_code = common::get_random_area_code();     
  22. stmt_with_area     
  23. .query()     
  24. .bind(area_code)     
  25. .bind(age)     
  26. .bind(is_active)     
  27. .execute(&mut tx)     
  28. .await?;     
  29. } else {     
  30. stmt.query()     
  31. .bind(age)     
  32. .bind(is_active)     
  33. .execute(&mut tx)     
  34. .await?;     
  35. }     
  36. }     
  37. tx.commit().await?;     
  38. Ok(())     
  39. }     
  40.  
  41. #[tokio::main]     
  42. async fn main() -> Result<(), sqlx::Error> {     
  43. let mut conn = SqliteConnectOptions::from_str("basic_async.db")     
  44. .unwrap()     
  45. .create_if_missing(true)     
  46. .journal_mode(SqliteJournalMode::Off)     
  47. .synchronous(SqliteSynchronous::Off)     
  48. .connect()     
  49. .await?;     
  50. conn.execute("PRAGMA cache_size = 1000000;").await?;     
  51. conn.execute("PRAGMA locking_mode = EXCLUSIVE;").await?;     
  52. conn.execute("PRAGMA temp_store = MEMORY;").await?;     
  53. conn.execute(     
  54. "CREATE TABLE IF NOT EXISTS user (     
  55. id INTEGER not null primary key,     
  56. area CHAR(6),     
  57. age INTEGER not null,     
  58. active INTEGER not null);",     
  59. )     
  60. .await?;     
  61. faker(conn, 100_000_000).await?;     
  62. Ok(())     

這個版本花了大約14分鐘。性能反而下降下降了。比Python版本還要差(原因值得深析)。

對執行的原始SQL語句,切換到準備好的語句并在循環中插入行,但重用了準備好的語句。該版本只用了大約一分鐘。

使用準備好的語句并將它們插入到50行的批次中,插入10億條,耗時34.3 秒。

  1. use rusqlite::{Connection, ToSql, Transaction}; 
  2. mod common; 
  3. fn faker_wrapper(mut conn: Connection, count: i64) { 
  4. let tx = conn.transaction().unwrap(); 
  5. faker(&tx, count); 
  6. tx.commit().unwrap(); 
  7. fn faker(tx: &Transaction, count: i64) { 
  8. // that is, we will batch 50 inserts of rows at once 
  9. let min_batch_size: i64 = 50
  10. if count < min_batch_size { 
  11. panic!("count cant be less than min batch size"); 
  12. // jeez, refactor this! 
  13. let mut with_area_params = " (NULL, ?, ?, ?),".repeat(min_batch_size as usize); 
  14. with_area_params.pop(); 
  15. let with_area_paramswith_area_params = with_area_params.as_str(); 
  16. let mut without_area_params = " (NULL, NULL, ?, ?),".repeat(min_batch_size as usize); 
  17. without_area_params.pop(); 
  18. let without_area_paramswithout_area_params = without_area_params.as_str(); 
  19. let st1 = format!("INSERT INTO user VALUES {}", with_area_params); 
  20. let st2 = format!("INSERT INTO user VALUES {}", without_area_params); 
  21. let mut stmt_with_area = tx.prepare_cached(st1.as_str()).unwrap(); 
  22. let mut stmt = tx.prepare_cached(st2.as_str()).unwrap(); 
  23. for _ in 0..(count / min_batch_size) { 
  24. let with_area = common::get_random_bool(); 
  25. let age = common::get_random_age(); 
  26. let is_active = common::get_random_active(); 
  27. let mut param_values: Vec<_> = Vec::new(); 
  28. if with_area { 
  29. // lets prepare the batch 
  30. let mut vector = Vec::<(String, i8, i8)>::new(); 
  31. for _ in 0..min_batch_size { 
  32. let area_code = common::get_random_area_code(); 
  33. vector.push((area_code, age, is_active)); 
  34. for batch in vector.iter() { 
  35. param_values.push(&batch.0 as &dyn ToSql); 
  36. param_values.push(&batch.1 as &dyn ToSql); 
  37. param_values.push(&batch.2 as &dyn ToSql); 
  38. stmt_with_area.execute(&*param_values).unwrap(); 
  39. } else { 
  40. // lets prepare the batch 
  41. let mut vector = Vec::<(i8, i8)>::new(); 
  42. for _ in 0..min_batch_size { 
  43. vector.push((age, is_active)); 
  44. for batch in vector.iter() { 
  45. param_values.push(&batch.0 as &dyn ToSql); 
  46. param_values.push(&batch.1 as &dyn ToSql); 
  47. stmt.execute(&*param_values).unwrap(); 
  48. fn main() { 
  49. let conn = Connection::open("basic_batched.db").unwrap(); 
  50. conn.execute_batch( 
  51. "PRAGMA journal_mode = OFF
  52. PRAGMA synchronous = 0
  53. PRAGMA cache_size = 1000000
  54. PRAGMA locking_mode = EXCLUSIVE
  55. PRAGMA temp_store = MEMORY;", 
  56. .expect("PRAGMA"); 
  57. conn.execute( 
  58. "CREATE TABLE IF NOT EXISTS user ( 
  59. id INTEGER not null primary key, 
  60. area CHAR(6), 
  61. age INTEGER not null, 
  62. active INTEGER not null)", 
  63. [], 
  64. .unwrap(); 
  65. faker_wrapper(conn, 100_000_000) 
  66. 創建了一個線程版本,其中有一個從通道接收數據的寫入線程和四個將數據推送到管道其他線程。 
  67. use rusqlite::{Connection, ToSql}; 
  68. use std::sync::mpsc; 
  69. use std::sync::mpsc::{Receiver, Sender}; 
  70. use std::thread; 
  71. mod common; 
  72. static MIN_BATCH_SIZE: i64 = 50
  73. enum ParamValues { 
  74. WithArea(Vec<(String, i8, i8)>), 
  75. WithoutArea(Vec<(i8, i8)>), 
  76. fn consumer(rx: Receiver<ParamValues>) { 
  77. let mut conn = Connection::open("threaded_batched.db").unwrap(); 
  78. conn.execute_batch( 
  79. "PRAGMA journal_mode = OFF
  80. PRAGMA synchronous = 0
  81. PRAGMA cache_size = 1000000
  82. PRAGMA locking_mode = EXCLUSIVE
  83. PRAGMA temp_store = MEMORY;", 
  84. .expect("PRAGMA"); 
  85. conn.execute( 
  86. "CREATE TABLE IF NOT EXISTS user ( 
  87. id INTEGER not null primary key, 
  88. area CHAR(6), 
  89. age INTEGER not null, 
  90. active INTEGER not null)", 
  91. [], 
  92. .unwrap(); 
  93. let tx = conn.transaction().unwrap(); 
  94. // jeez, refactor this! 
  95. let mut with_area_params = " (NULL, ?, ?, ?),".repeat(MIN_BATCH_SIZE as usize); 
  96. with_area_params.pop(); 
  97. let with_area_paramswith_area_params = with_area_params.as_str(); 
  98. let mut without_area_params = " (NULL, NULL, ?, ?),".repeat(MIN_BATCH_SIZE as usize); 
  99. without_area_params.pop(); 
  100. let without_area_paramswithout_area_params = without_area_params.as_str(); 
  101. let st1 = format!("INSERT INTO user VALUES {}", with_area_params); 
  102. let st2 = format!("INSERT INTO user VALUES {}", without_area_params); 
  103. let mut stmt_with_area = tx.prepare_cached(st1.as_str()).unwrap(); 
  104. let mut stmt_without_area = tx.prepare_cached(st2.as_str()).unwrap(); 
  105. for param_values in rx { 
  106. let mut row_values: Vec<&dyn ToSql> = Vec::new(); 
  107. match param_values { 
  108. ParamValues::WithArea(values) => { 
  109. for batch in values.iter() { 
  110. row_values.push(&batch.0 as &dyn ToSql); 
  111. row_values.push(&batch.1 as &dyn ToSql); 
  112. row_values.push(&batch.2 as &dyn ToSql); 
  113. stmt_with_area.execute(&*row_values).unwrap(); 
  114. ParamValues::WithoutArea(values) => { 
  115. for batch in values.iter() { 
  116. row_values.push(&batch.0 as &dyn ToSql); 
  117. row_values.push(&batch.1 as &dyn ToSql); 
  118. stmt_without_area.execute(&*row_values).unwrap(); 
  119. tx.commit().unwrap(); 
  120. fn producer(tx: Sender<ParamValues>, count: i64) { 
  121. if count < MIN_BATCH_SIZE { 
  122. panic!("count cant be less than min batch size"); 
  123. for _ in 0..(count / MIN_BATCH_SIZE) { 
  124. let with_area = common::get_random_bool(); 
  125. let age = common::get_random_age(); 
  126. let is_active = common::get_random_active(); 
  127. let mut param_values: Vec<_> = Vec::new(); 
  128. if with_area { 
  129. // lets prepare the batch 
  130. let mut vector = Vec::<(String, i8, i8)>::new(); 
  131. for _ in 0..MIN_BATCH_SIZE { 
  132. let area_code = common::get_random_area_code(); 
  133. vector.push((area_code, age, is_active)); 
  134. for batch in vector.iter() { 
  135. param_values.push(&batch.0 as &dyn ToSql); 
  136. param_values.push(&batch.1 as &dyn ToSql); 
  137. param_values.push(&batch.2 as &dyn ToSql); 
  138. // send the values 
  139. tx.send(ParamValues::WithArea(vector)).unwrap(); 
  140. } else { 
  141. // lets prepare the batch 
  142. let mut vector = Vec::<(i8, i8)>::new(); 
  143. for _ in 0..MIN_BATCH_SIZE { 
  144. vector.push((age, is_active)); 
  145. for batch in vector.iter() { 
  146. param_values.push(&batch.0 as &dyn ToSql); 
  147. param_values.push(&batch.1 as &dyn ToSql); 
  148. // send the values 
  149. tx.send(ParamValues::WithoutArea(vector)).unwrap(); 
  150. fn main() { 
  151. // setup the DB and tables 
  152. let (tx, rx): (Sender<ParamValues>, Receiver<ParamValues>) = mpsc::channel(); 
  153. // lets launch the consumer 
  154. let consumer_handle = thread::spawn(|| consumer(rx)); 
  155. let cpu_count = num_cpus::get(); 
  156. let total_rows = 100_000_000
  157. let each_producer_count = (total_rows / cpu_count) as i64; 
  158. let mut handles = Vec::with_capacity(cpu_count); 
  159. for _ in 0..cpu_count { 
  160. let thread_tx = tx.clone(); 
  161. handles.push(thread::spawn(move || { 
  162. producer(thread_tx, each_producer_count.clone()) 
  163. })) 
  164. for t in handles { 
  165. t.join().unwrap(); 
  166. drop(tx); 
  167. // wait till consumer is exited 
  168. consumer_handle.join().unwrap(); 

這是性能最好的版本,耗時約32.37秒。

基準測試對比:

總結

通過案例不同任務實驗,總體上可以得到:

  • 通過SQLite PRAGMA語句優化設置可以提高插入性能。
  • 使用準備好的語句可以提高性能
  • 進行批量插入可以提高性能。
  • PyPy 實際上比CPython快4倍
  • 線程/異步不一定能提高性能。

 

責任編輯:趙寧寧 來源: 蟲蟲搜奇
相關推薦

2021-07-19 15:33:27

編程Rust開發

2011-05-25 10:32:19

SQLite

2024-04-15 08:30:53

MySQLORM框架

2024-07-04 13:42:12

2025-06-26 08:22:03

2025-05-12 01:55:00

MySQL存儲數據

2024-05-21 11:34:03

RustPython編譯器

2024-06-24 07:00:00

C++RustGo

2015-03-03 09:52:02

2022-11-17 10:23:13

VS CodeCodiumPython

2018-06-21 09:12:01

編程語言Python數據分析

2022-04-06 14:15:10

Python數據

2024-01-08 13:31:00

Rust自動化測試

2025-09-28 00:00:01

RustPython語言

2024-06-04 10:49:05

Rust插件開發工具

2023-03-07 17:50:03

2024-04-02 08:30:40

RustUnix信號服務器

2021-08-22 17:22:31

VS Code容器開發人員

2022-01-14 10:50:23

PythonRust編程語言

2024-09-20 18:02:42

C#數據庫SQLite
點贊
收藏

51CTO技術棧公眾號

日韩一区二区av| 色吊一区二区三区| 成人综合av网| 国产精品久久久久久久久久久久久久久久久 | 91国产精品一区| 婷婷六月综合| 日韩欧美www| 欧美 日本 亚洲| 无码人妻一区二区三区在线| 免费观看a视频| 国产日韩欧美高清免费| 国产一区二区黑人欧美xxxx| 欧美一区二区三区久久精品| 亚洲最大成人综合| 精品欧美日韩在线| 青青草成人免费在线视频| 成人性生活毛片| 成人免费在线电影网| 99亚洲一区二区| 国产视频久久久久| 不用播放器的免费av| 99thz桃花论族在线播放| 久久久午夜精品| 亚洲xxxxx性| 97碰在线视频| 国产无套粉嫩白浆在线2022年| 国产曰批免费观看久久久| 欧美做受高潮1| 美女福利视频在线观看| 成人看的视频| 亚洲第一色在线| 污污网站在线观看视频| 91久久国产综合久久91猫猫| 亚洲乱码国产乱码精品精可以看 | 精品亚洲porn| 国产91热爆ts人妖在线| 精品无码一区二区三区电影桃花| 日韩在线欧美| 亚洲人成77777在线观看网| youjizz.com日本| www一区二区三区| 欧美午夜宅男影院| 亚洲爆乳无码专区| 久草免费在线视频| 亚洲成人免费观看| 久久男人资源站| www在线观看播放免费视频日本| 国产三级一区二区| 欧美日韩精品久久| 三区在线观看| 99久久精品免费精品国产| 99中文视频在线| 国产青青草视频| 久久er精品视频| 国产在线精品一区免费香蕉| 欧美 亚洲 另类 激情 另类| 久久一区精品| 国产不卡在线观看| 69视频免费看| 日本成人中文字幕在线视频 | 一区二区三区我不卡| 免费a在线观看| 97久久精品人人澡人人爽| 激情小说网站亚洲综合网 | 伊人久久av| 欧美日韩国产丝袜另类| 欧美在线观看成人| 欧美成人资源| 欧美性猛交xxxxxxxx| 少妇一级淫免费放| 亚洲热av色在线播放| 宅男在线国产精品| 国产伦精品一区二区三区妓女下载| 国产色99精品9i| 欧美电影免费提供在线观看| 美女黄色一级视频| 亚洲另类春色校园小说| 一本大道久久加勒比香蕉| jizzjizzjizz国产| 中文字幕一区二区三区乱码图片| 久久成人18免费网站| 久久精品无码人妻| 麻豆精品网站| 国产综合福利在线| 秋霞视频一区二区| 国产色91在线| 免费cad大片在线观看| √最新版天堂资源网在线| 色综合天天天天做夜夜夜夜做| 不卡av免费在线| 国产精品日韩精品在线播放| 亚洲成人久久久| 少妇无套高潮一二三区| 久久久久久影院| 97精品免费视频| 亚洲 日本 欧美 中文幕| 奇米精品一区二区三区在线观看| 国产精品美女视频网站| 亚洲成人第一区| 久久久噜噜噜久久人人看| 亚洲一二区在线| 超碰在线网站| 欧美色国产精品| 中文字幕在线播放一区二区| 天天做夜夜做人人爱精品| 色综久久综合桃花网| 国产在线欧美在线| 免播放器亚洲一区| 精品国产乱码久久久久久郑州公司 | 亚洲一区二区三区中文字幕| 日韩 欧美 高清| 麻豆国产一区| 国产一区二区三区在线观看网站| 乱h高h女3p含苞待放| 久久这里有精品15一区二区三区| 亚洲一区国产精品| 成人精品一区二区三区校园激情 | 日韩黄色精品视频| 男人的天堂亚洲一区| 精品国产福利| 女同视频在线观看| 欧美另类z0zxhd电影| 香蕉视频黄色在线观看| 国产一区视频在线观看免费| 国产在线a不卡| 精品视频一二区| 亚洲国产欧美一区二区三区丁香婷| 免费观看成人网| aaaa欧美| 亚洲日韩欧美视频| 在线观看国产亚洲| 成人国产精品视频| www.欧美黄色| 久久爱www.| 日韩专区在线观看| 九九热最新视频| 91丨九色丨蝌蚪丨老版| 九色自拍视频在线观看| 日韩一区二区三区色| 久久精品视频一| 国产一级片一区二区| 久久综合给合久久狠狠狠97色69| 精品少妇人欧美激情在线观看| 国产日韩欧美中文在线| 久久精品国产欧美激情| 国产又大又长又粗| 中文字幕一区二区三区不卡 | 欧美日韩一区在线观看视频| 17videosex性欧美| 欧美精品一区二区久久婷婷| 男女羞羞免费视频| 国产成a人亚洲| 老司机激情视频| 精品国产亚洲一区二区三区| 久久综合久久88| 99久久久国产精品无码免费| 亚洲色图欧洲色图婷婷| 亚洲无在线观看| 一区二区在线影院| 51国偷自产一区二区三区的来源| 久久久久久国产精品免费无遮挡| 正在播放一区二区| 国产精品白嫩白嫩大学美女| 国产福利一区二区三区| 隔壁人妻偷人bd中字| 国产伦理久久久久久妇女 | 亚洲第一区在线| 中文字幕亚洲精品在线| 久久久久久久久久久99999| 99免费视频观看| japanese国产精品| 国产欧美日韩中文字幕在线| 国产写真视频在线观看| 精品乱人伦小说| 成年人免费高清视频| 国产日韩欧美一区二区三区乱码 | 欧美一区二区三区男人的天堂| 国产福利视频网站| 高潮精品一区videoshd| 日本精品免费在线观看| 日韩综合一区| 高清免费日韩| 日韩精品一区二区三区| 精品国产视频在线| 俄罗斯嫩小性bbwbbw| 日韩欧美中文免费| 久久久99999| 波多野结衣在线一区| av视屏在线播放| 牛牛国产精品| 欧美日韩国产精品一区二区| 99国内精品久久久久| 91国产精品电影| 色欧美激情视频在线| 精品国产乱码久久久久久免费| 日韩精品一区不卡| 亚洲精品高清在线| www在线观看免费视频| 国产乱国产乱300精品| 国产日韩一区二区在线| 国产精品99久久久久久动医院| 国产精品对白刺激久久久| 日本h片久久| 久久久久亚洲精品成人网小说| 国产鲁鲁视频在线观看免费| 精品久久久久一区二区国产| www.av88| 亚洲午夜三级在线| 超碰97av在线| 99国产精品99久久久久久| 中文字幕成人免费视频| 亚洲综合日本| www成人免费| 色综合久久五月| 国产主播精品| 久久国产主播精品| 欧美午夜网站| 国产精品美女主播在线观看纯欲| 日韩电影免费观看| 有码中文亚洲精品| 无码国产伦一区二区三区视频 | 电影一区中文字幕| 日韩免费高清在线观看| heyzo一区| 久久久精品国产亚洲| 可以在线观看的av| 日韩乱码在线视频| 天天综合网在线观看| 日韩三级中文字幕| 国产又大又黑又粗| 欧美日韩精品系列| 波多野结衣一本一道| 色综合久久中文综合久久牛| 精品视频久久久久| 一区二区三区欧美日韩| 天天做夜夜爱爱爱| 国产精品全国免费观看高清 | 国产成人精品一区二区色戒| 欧美日韩国产丝袜另类| 国产精品a成v人在线播放| 亚洲免费在线观看视频| 成人免费精品动漫网站| 中文字幕日韩一区| 日韩欧美视频免费观看| 国产精品日日摸夜夜摸av| 国产精品一二三区在线观看| 久久综合久久99| 欧美深性狂猛ⅹxxx深喉 | 亚洲91视频| 超碰成人在线免费观看| 久久网站免费观看| eeuss中文| 亚洲美女视频| 国产又粗又大又爽的视频| 911久久香蕉国产线看观看| 在线观看精品视频| 久久久久美女| www.男人天堂网| 激情综合中文娱乐网| 可以看毛片的网址| 国产精品一二| 波多野结衣作品集| 美腿丝袜在线亚洲一区| 女人高潮一级片| 国产剧情在线观看一区二区| 师生出轨h灌满了1v1| 99天天综合性| 在线观看日本中文字幕| 国产精品丝袜91| 欧美丰满熟妇bbbbbb| 亚洲成人一区在线| 色老头一区二区| 欧美久久婷婷综合色| www.激情五月| 亚洲第一福利网| 免费黄色在线视频网站| 日韩中文字幕不卡视频| aa在线视频| 青青草一区二区| 日本成人在线网站| 高清国产在线一区| 欧美激情在线免费| 手机成人av在线| 亚洲毛片一区| av丝袜天堂网| 国产精品99久久不卡二区| 国产精品久久不卡| 国产精品久久免费看| 国产亚洲精品码| 色婷婷综合久久久中文一区二区 | 蜜臀精品一区二区三区在线观看| 久久久福利影院| 91婷婷韩国欧美一区二区| 国产男女猛烈无遮挡在线喷水| 亚洲国产精品久久一线不卡| 波多野结衣视频在线看| 日韩精品专区在线影院观看| 美国一级片在线免费观看视频| 久久精品国产亚洲精品2020| 日本伊人色综合网| 中文字幕免费高清在线| 成人亚洲一区二区一| x88av在线| 一区二区三区精品视频在线| 丁香六月婷婷综合| 91麻豆精品国产91久久久久| 天天爽夜夜爽夜夜爽| 爽爽爽爽爽爽爽成人免费观看| 日本三级在线观看网站| 国产成人精品久久二区二区91| 亚洲精品视频在线观看免费视频| 婷婷久久综合九色国产成人| 中文字幕人成人乱码亚洲电影| 日韩精品中午字幕| 成人影院免费观看| 国内精久久久久久久久久人| 欧美啪啪网站| 久久精品99| 在线国产一区二区| 亚洲成人福利在线观看| av成人免费在线观看| 日韩激情小视频| 欧美性一二三区| 五月婷婷在线观看视频| 色在人av网站天堂精品| 日本一区二区中文字幕| 欧美一区二区影视| 亚洲美女视频在线免费观看| 成人免费播放视频| 中文字幕日韩一区二区| 中文字幕乱码人妻无码久久| 亚洲精品一二区| av资源在线| 成人自拍偷拍| 欧美激情一级片一区二区| 日本中文字幕观看| 亚洲国产精品成人久久综合一区 | 亚洲精品菠萝久久久久久久| 国产美女www| 亚洲人午夜色婷婷| 97成人资源| 欧美日韩精品久久| 久久裸体视频| 色一情一交一乱一区二区三区| 欧美午夜精品久久久久久浪潮| 亚洲欧美另类日韩| 欧美国产日韩一区二区在线观看 | 日韩欧美亚洲综合| 头脑特工队2免费完整版在线观看| 欧美高清激情视频| 日日夜夜精品视频| 日韩一二区视频| 国产精品一二三四| 好吊色视频在线观看| 日韩亚洲欧美高清| 日本在线视频www鲁啊鲁| 99视频免费观看| 欧美视频成人| 亚洲天堂2024| 精品女同一区二区三区在线播放| 五月天丁香视频| 欧洲美女7788成人免费视频| 欧美日韩爱爱| 污污网站免费看| 亚洲欧洲av一区二区三区久久| 国产精品无码久久av| 九九热精品视频国产| 爱高潮www亚洲精品| 免费成人在线视频网站| 国产婷婷精品av在线| 夜夜狠狠擅视频| 欧美理论电影在线观看| 综合中文字幕| 人妻精品无码一区二区三区 | 久久爱av电影| 天堂成人免费av电影一区| 日本视频在线免费| 日韩视频免费观看高清在线视频| 欧美理论电影| 欧美日韩在线观看一区二区三区| 免费在线看一区| 放荡的美妇在线播放| 欧美精品一区二区在线观看| 大胆人体一区二区| 在线视频不卡一区二区三区| 风间由美性色一区二区三区| 毛片视频网站在线观看| 色偷偷噜噜噜亚洲男人的天堂| 视频精品一区| 日韩av资源在线| 国产精品国产三级国产aⅴ中文| 精品人妻无码一区二区色欲产成人 | 欧美视频国产视频| 午夜欧美一区二区三区在线播放| 精品久久久久一区二区三区 | 日韩一区二区欧美| 97久久综合精品久久久综合| 中文字幕无码不卡免费视频| 亚洲视频免费看| 欧洲免费在线视频|