精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

亚洲精品视频自拍| 蜜桃视频在线观看一区二区| 日韩电影中文字幕在线| 日本免费观看网站| 中文字幕中文字幕在线十八区 | 奇米影视888狠狠狠777不卡| 蜜臀av性久久久久蜜臀aⅴ | 亚洲视频免费一区| 一级做a爱视频| 是的av在线| 中文字幕在线一区二区三区| 国产美女精品在线观看| 日本视频www色| 国户精品久久久久久久久久久不卡| 亚洲激情视频在线| 久久6免费视频| 原纱央莉成人av片| 亚洲午夜成aⅴ人片| 亚洲一区三区电影在线观看| 欧美自拍第一页| 久久国产精品一区二区| 97热精品视频官网| 污软件在线观看| 欧美丝袜一区| 精品久久久久久久久久久久包黑料 | 日本vs亚洲vs韩国一区三区| 欧美精品久久久久久久久| a资源在线观看| 亚洲激情播播| 精品成人一区二区| 男女污污视频网站| 姬川优奈av一区二区在线电影| 亚洲精品欧美激情| 在线观看日本一区| 国产小视频免费在线网址| 粉嫩嫩av羞羞动漫久久久| 国产欧美在线观看| 免费污污视频在线观看| 亚洲精品日本| 欧美精品久久久久| 激情综合五月网| 久久久久久久久久久妇女| 在线a欧美视频| xxx在线播放| 免费视频国产一区| 精品视频—区二区三区免费| 亚洲图片欧美另类| 97人人澡人人爽91综合色| 日韩欧美在线综合网| www激情五月| 99精品国产九九国产精品| 在线中文字幕不卡| 无码人妻精品一区二区三区66| 中文一区一区三区高中清不卡免费| 亚洲一区二区视频在线| 欧美黄色免费网址| 青草视频在线免费直播| 亚洲一级电影视频| 少妇高潮喷水在线观看| 黄色激情在线播放| 日韩欧美中文第一页| 美女福利视频在线| 性欧美hd调教| 欧美视频精品在线观看| 色婷婷成人在线| 91成人短视频在线观看| 欧美精品乱人伦久久久久久| 九九热视频免费| 最新国产精品精品视频| 精品99一区二区| 亚洲观看黄色网| 美女久久99| 中文字幕九色91在线| 三级黄色录像视频| 天天插综合网| 欧美精品激情在线观看| 9i看片成人免费看片| 日韩av一区二区在线影视| 国产精品成人免费电影| 在线观看色网站| 国产一区二区三区在线观看免费视频 | 澳门精品久久国产| 亚洲欧美日韩网| 性爱在线免费视频| 亚洲有吗中文字幕| 国模精品系列视频| 午夜一级黄色片| 狠狠色丁香久久婷婷综| 国产精品一区二区三区不卡| 免费av在线电影| 国产精品美女久久久久久久久久久 | 超鹏97在线| 精品久久在线播放| 91人人澡人人爽人人精品| 国产成人免费av一区二区午夜| 精品国产亚洲一区二区三区在线观看| 国产亚洲无码精品| 91亚洲自偷观看高清| 久久免费视频网站| 最近中文字幕在线免费观看| 高清久久久久久| 视频在线一区二区三区| 国产第一页在线视频| 日本精品免费观看高清观看| 日本成人xxx| 你懂的视频欧美| 欧美韩日一区二区| 伊人久久一区二区| 91一区一区三区| 好色先生视频污| 欧美色网在线| 欧美精品一区二区三区蜜臀 | 亚洲综合无码一区二区| 亚洲性生活网站| 九九热hot精品视频在线播放 | 手机av在线看| 久久婷婷麻豆| 精品午夜一区二区| 在线看女人毛片| 欧美三级乱人伦电影| 国产白嫩美女无套久久| 中文字幕人成人乱码| 国产精品午夜一区二区欲梦| 天天干天天插天天操| **性色生活片久久毛片| 少妇高清精品毛片在线视频| 极品国产人妖chinesets亚洲人妖| 久久激情五月丁香伊人| 波多野结衣不卡| 91最新地址在线播放| 免费人成在线观看视频播放| 亚洲欧美专区| www.日韩免费| 自拍偷拍精品视频| 国产喂奶挤奶一区二区三区| 日韩av在线第一页| 久久精品亚洲成在人线av网址| 欧美日韩成人黄色| 99热这里只有精品9| 国产精品人人做人人爽人人添| 国产男女激情视频| 夜夜春成人影院| 欧美一级高清免费播放| 懂色av蜜臀av粉嫩av分享吧| 一区二区日韩av| 真实乱偷全部视频| 欧美国产先锋| 999视频在线观看| 操你啦视频在线| 日韩精品一区二区三区在线观看| √天堂中文官网8在线| 精油按摩中文字幕久久| 在线视频不卡一区二区| 少妇高潮一区二区三区99| www.日韩系列| 99精品免费观看| 一区二区三区资源| 国产免费a级片| 在线看片一区| 欧美一区二区在线视频观看| 日日av拍夜夜添久久免费| 国产一区二区三区久久精品| 在线视频精品免费| 日韩一区日韩二区| 国产毛片久久久久久| 国产精品多人| 精品久久蜜桃| 国产成人亚洲一区二区三区| 久久精品国产欧美亚洲人人爽| 999免费视频| 亚洲成人7777| 国产成人无码精品久久二区三| 可以看av的网站久久看| 色噜噜色狠狠狠狠狠综合色一| 久久er热在这里只有精品66| 欧美xxxx做受欧美| 色中色在线视频| 欧美系列在线观看| www.xxxx日本| 337p粉嫩大胆噜噜噜噜噜91av| 无码aⅴ精品一区二区三区浪潮 | 国产精品videossex国产高清| 99精品在免费线中文字幕网站一区| 97在线观看视频| 98在线视频| 日韩欧美国产三级| 欧美日韩一二三四区| 国产精品久久久久久久久图文区 | 51ⅴ精品国产91久久久久久| www.在线视频.com| 精品1区2区在线观看| 蜜臀尤物一区二区三区直播| 亚洲综合免费观看高清在线观看| 9.1成人看片免费版| 蜜桃在线一区二区三区| 黄色一级视频在线播放| 久久精品av| 精品日韩欧美| 精品午夜av| 日本久久久久亚洲中字幕| 亚洲精品天堂| 夜夜躁日日躁狠狠久久88av| 成人久久久精品国产乱码一区二区| 91福利区一区二区三区| 日本免费在线播放| 中文字幕一区二区三区四区不卡| 99久久免费看精品国产一区| 国产一本一道久久香蕉| 苍井空浴缸大战猛男120分钟| 亚洲欧美综合| 亚洲一区二区三区免费看| 国产在线播放精品| 成人国产精品日本在线| 欧美成人黑人| 午夜精品久久久久久久99热浪潮| 国产欧美久久久久久久久| 亚洲一区二区精品| 天天av天天翘| 欧美成人一区二区| 中文字幕人妻丝袜乱一区三区| 午夜欧美视频在线观看| 四虎影院中文字幕| 欧美国产成人精品| 欧美bbbbb性bbbbb视频| 成人少妇影院yyyy| 国产精品探花在线播放| 久久精品国产免费看久久精品| 免费日韩视频在线观看| 亚洲激情网站| 日韩精品一区二区免费| 亚洲精品99| 伊人久久av导航| 成人在线丰满少妇av| 欧美婷婷久久| 自拍亚洲一区| 欧美日韩一区二| 久久爱www成人| 日本一区不卡| 禁断一区二区三区在线| 欧美久久在线| 国产成人影院| 日本一区高清不卡| 欧美色蜜桃97| 亚洲一区免费看| 国产精品久久久乱弄| 亚洲免费看黄网站| 欧美影视一区二区| 米奇777超碰欧美日韩亚洲| 狠狠色噜噜狠狠狠狠色吗综合| 51精品国产| 国产欧美日韩综合精品二区| 日韩在线精品强乱中文字幕| 91在线观看网站| 97精品久久| 狠狠色噜噜狠狠狠狠色吗综合| 粉嫩精品导航导航| 国产亚洲自拍偷拍| 亚欧日韩另类中文欧美| 免费看成人片| 成人6969www免费视频| 午夜精品视频在线观看一区二区| 成人羞羞网站入口| 亚洲av首页在线| 欧美激情第10页| 欧美a v在线播放| 秋霞成人午夜伦在线观看| 在线观看亚洲色图| 国产呦精品一区二区三区网站| 无套白嫩进入乌克兰美女| 国产成人精品免费在线| 男男做爰猛烈叫床爽爽小说| 2020国产精品自拍| 制服丨自拍丨欧美丨动漫丨| 玉足女爽爽91| 久久国产视频播放| 欧美午夜精品一区二区蜜桃 | 欧美高清www午色夜在线视频| 97人妻精品一区二区三区动漫 | 黄色在线小视频| www.日韩不卡电影av| 福利成人导航| 国产精品成人av性教育| 天堂va在线高清一区| 久久久久高清| 99精品在线| 国产黄色一级网站| 极品美女销魂一区二区三区免费| 91精产国品一二三| 久久久久久久精| 日韩影院一区二区| 色综合天天综合网国产成人综合天| 亚洲一级av毛片| 亚洲成人av片| 欧美69xxx| 国产91精品高潮白浆喷水| 高清欧美日韩| 久久天天狠狠| 欧美 日韩 国产 一区| 久久精品99国产| 国产精品一区在线| 亚洲 小说 欧美 激情 另类| 一区二区三区国产| 亚洲综合网av| 精品丝袜一区二区三区| www免费视频观看在线| 日韩av色在线| 国语一区二区三区| 最新精品视频| 久久久久久久波多野高潮日日| 在线成人精品视频| 国产精品久久久久久久岛一牛影视| 国产大片中文字幕| 7777精品伊人久久久大香线蕉最新版| 四虎精品在线| 欧美精品18videos性欧美| 亚洲午夜国产成人| 日本不卡二区高清三区| 99av国产精品欲麻豆| 91网址在线观看精品| 中文字幕乱码一区二区免费| 国产又黄又猛又粗又爽| 精品国产露脸精彩对白 | 欧美黑人巨大精品一区二区| 久久精品资源| 欧洲精品亚洲精品| 国产精品日本| 六十路息与子猛烈交尾| 亚洲图片欧美一区| 超碰人人人人人人| 久久久精品国产亚洲| 日韩有码欧美| 亚洲一区二区自拍偷拍| 日本欧美一区二区| 国产小视频自拍| 色狠狠一区二区三区香蕉| 色资源在线观看| 2018国产精品视频| 欧美美女在线直播| 男人添女荫道口图片| 国产69精品久久99不卡| 国产亚洲精品久久久久久打不开| 欧美一区二区在线免费播放| free性欧美hd另类精品| 亚洲在线一区二区| 欧美日韩福利| 美女网站视频在线观看| 亚洲午夜羞羞片| 女人18毛片水真多18精品| 欧美激情在线播放| 97超碰成人| av黄色在线网站| 久久久高清一区二区三区| 国产中文字幕视频| 国产一区二区三区在线| 日韩漫画puputoon| 中文字幕人成一区| 国产大片一区二区| 日韩免费一二三区| 亚洲精选在线观看| 草民电影神马电影一区二区| 亚洲一区二区三区四区中文| 国产精品一卡二卡| 日本在线视频中文字幕| 日韩精品免费视频| 成人全视频在线观看在线播放高清| 午夜久久资源| 国产精品一区一区三区| 69精品久久久| 尤物yw午夜国产精品视频| 亚洲欧洲一二区| 欧美一级欧美一级| 国产欧美日韩另类视频免费观看 | 欧美xxxxxxxxx| 成人一区福利| 在线免费一区| 99久久精品一区二区| 波多野结衣视频免费观看| 久久精品国产视频| 久久porn| 亚洲国产日韩欧美在线观看| 亚洲免费在线看| 五月天激情婷婷| 成人春色激情网| 亚洲免费黄色| 成人黄色短视频| 日韩av影院在线观看| 欧美美女福利视频| 人妻少妇精品无码专区二区| 日本一区二区三区高清不卡| www黄色网址| 国产精品久久久久av| 国一区二区在线观看| 人妻少妇无码精品视频区| 日韩欧美综合一区| 国产综合色区在线观看| 91视频 - 88av| 国产精品免费aⅴ片在线观看| 国产 日韩 欧美 精品| 国产一区二区在线播放| 国产精品视频|