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

從MySQL JOIN 算法角度看如何優化SQL

數據庫 MySQL
Block Nested-Loop Join (Hash Join)與 Index Nested-Loop Join 對比,并沒有哪一種算法更優一說,只要其整體成本比另一種低,那他就是最合適的。

一、前言

在做MySQL的SQL優化時,如果只涉及到單表查詢,那么大部分慢SQL都只需從索引上入手優化即可,通過添加合適的索引來消除全表掃描或者排序操作,執行效果,大概率能實現質的飛躍。

然而,在實際生產中,除了單表查詢,更多的是多個表的聯合查詢,這樣的查詢通常是慢SQL的重災區,查詢速度慢,且使用服務器資源較多,如果能將這類SQL優化掉,那必將大大減輕數據庫服務器壓力。現在,咱就通過多表關聯內部數據操作的角度,看看如何進行SQL優化。

二、準備工作

現在線上環境大部分使用的都是MySQL 5.7.x版本,那咱就以5.7版本為主,適當延伸MySQL 8.0版本為輔進行講解測試。

創建測試表:

# 創建兩個表結構一模一樣的表:t1、t2
create table t1(
  id int not null auto_increment,
  a int,
  b int,
  c int,
  primary key(id),
  key idx_a(a)
);


create table t2 like t1;

構造測試數據:

# 創建2個存儲過程用于構造測試數據


# 構造t1表數據的存儲過程,數據為3的整除數,1000條
delimiter //
create procedure t1_proc()
begin
    declare i int default 1;
    while (i<=3000) do
        if (i%3) = 0 then
            insert into t1(a,b,c) values(i, i, i);
        end if;
        set i=i+1;
    end while;
end //
delimiter ;




# 構造t2表數據的存儲過程,數據為2的整除數,100000條
delimiter //
create procedure t2_proc()
begin
    declare i int default 1;
    while (i<=200000) do
        if (i%2) = 0 then
            insert into t2(a,b,c) values(i, i, i);
        end if;
        set i=i+1;
    end while;
end //
delimiter ;


# 調用存儲過程,生成測試數據
call t1_proc();
call t2_proc();


# 刪除存儲過程
drop procedure t1_proc;
drop procedure t2_proc;

數據樣例:

[5.7.37-log localhost:mysql.sock]>select * from t1 limit 5;
+----+------+------+------+
| id | a    | b    | c    |
+----+------+------+------+
|  1 |    3 |    3 |    3 |
|  2 |    6 |    6 |    6 |
|  3 |    9 |    9 |    9 |
|  4 |   12 |   12 |   12 |
|  5 |   15 |   15 |   15 |
+----+------+------+------+
5 rows in set (0.00 sec)


[5.7.37-log localhost:mysql.sock]>select * from t2 limit 5;
+----+------+------+------+
| id | a    | b    | c    |
+----+------+------+------+
|  1 |    2 |    2 |    2 |
|  2 |    4 |    4 |    4 |
|  3 |    6 |    6 |    6 |
|  4 |    8 |    8 |    8 |
|  5 |   10 |   10 |   10 |
+----+------+------+------+
5 rows in set (0.00 sec)

三、MySQL JOIN算法

MySQL對兩表關聯,支持多種Join算法,咱就以下面這個SQL為例,深入探討一下。

測試SQL:

select * from t1 join t2 on t1.b=t2.b;

1、Simple Nested-Loop Join

設想一下,如果兩表關聯,在沒有任何干預的情況下,他像不像下面這個偽代碼的嵌套循環:

for row_1 in t1: # 循環1000次
    for row_2 in t2: # 對應每個外層循環10w次
        if row_1.b == row_2.b:
            do something

從上面的偽代碼中,我們可以看到,其就是簡單粗暴的嵌套循環,我們將其稱為 Simple Nested-Loop Join。回到數據庫層面,在測試SQL兩個表關聯的過程中,t1表中的每一行數據,都會觸發掃描一次t2表的數據,然后進行數據匹配。總的來講就是,因為t1表有1000行數據,所以t2表會被掃描1000次,并進行1000 * 10w = 1億次數據比較。

圖片圖片

很顯然,如果使用這種方式,當 t2 表足夠大時,反復掃描數據的過程中,磁盤必然會被拉爆,服務器性能會急劇下降。像MySQL這樣優秀的產品,必然會想方設法的避免這種情況的發生。

2、Block Nested-Loop Join

緊接上面所說,既然 Simple Nested-Loop Join最大的弊端是被驅動表被反復掃描,那是不是可以從這方面入手,減少被驅動表的掃描次數,以達到優化目的。咱繼續往下看,看他是怎么實現的。

一般情況下,兩表關聯,MySQL都會將結果集小(指根據條件過濾后)的表做驅動表,結果集大的表當被驅動表,那是不是可以嘗試一下,把驅動表的結果集放到內存中(Join Buffer),然后一次性掃描被驅動表的所有數據,反過來與Join Buffer中的驅動表結果集進行比較。這方式,驅動表和被驅動表都只掃描一次,但在內存中進行數據比較的次數依然為 10w * 1000 = 1億次。很顯然,這方式,相對于Simple Nested-Loop Join而言,優勢非常明顯,MySQL管這個叫Block Nested-Loop Join。

圖片圖片

聰明的你,是不是在想:如果驅動表t1的結果集,無法一次性全部存放到Join Buffer內存中時,怎么辦?

Join Buffer 的大小由參數 join_buffer_size 控制,默認為256K。在使用Join Buffer時,如果無法一次性存放所有結果集,他會分多次進行,比如:

1)讀取驅動表t1的數據,存放到Join Buffer中,假設,存放400條后,Join Buffer滿了,停止讀取

2)讀取被驅動表t2的數據,每一行數據都與Join Buffer中的數據進行比較,并返回符合條件的結果集

3)清空Join Buffer

4)繼續讀取驅動表t1的數據,將401-800的數據存放到Join Buffer,直到存滿

5)...... 繼續重復相似的動作,直到所有數據都比對完

圖片圖片

在上述假設情況下,因Join Buffer大小限制的原因,被驅動表 t2 被掃描了3次。總的來講,雖然不算完美,但顯然比使用Simple Nested-Loop Join的方式容易接受多了。也就是說,MySQL在經過對表鏈接進行優化后,就不會再出現使用Simple Nested-Loop Join的情況了。

執行計劃:

[5.7.37-log localhost:mysql.sock]>explain select * from t1 join t2 on t1.b=t2.b\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 100.00
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 100256
     filtered: 10.00
        Extra: Using where; Using join buffer (Block Nested Loop)
2 rows in set, 1 warning (0.00 sec)

3、Hash Join

雖然經過MySQL優化后的 Block Nested-Loop Join 算是改進了不少,但是,對各位程序員大拿而言,必然是一眼就看出了還有改進的余地。

Block Nested-Loop Join 在將驅動表結果集存放到Join Buffer后,被驅動表的數據與其比對時,被驅動表的每一行數據,都要與Join Buffer中所有數據進行比對,才能得出匹配的結果。這像不像對MySQL實體表進行條件查詢時,進行了全表掃描的操作一樣。這情況,如果給條件列加個索引,查詢速度是不是要瞬間起飛。

想法很好,但很不幸,MySQL 5.7.x 版本不支持;但也很慶幸,MySQL 8.0版本實現了,他會根據驅動表結果集,將關聯列映射為哈希值后鍵創建哈希表,被驅動表的數據在與哈希表進行比較時,就大大降低了比較次數,這也達到了優化的目的,我們管其叫Hash Join。

圖片圖片

咱看看其執行計劃:

[8.0.27 127.0.0.1:3380]>explain select * from t1 join t2 on t1.b=t2.b\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 100.00
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 100400
     filtered: 10.00
        Extra: Using where; Using join buffer (hash join)
2 rows in set, 1 warning (0.00 sec)

咱再來對比一下Block Nested-Loop Join和Hash Join的執行速度:

[5.7.37-log localhost:mysql.sock]>select * from t1 join t2 on t1.b=t2.b;
......
+------+------+------+------+------+------+
500 rows in set (4.90 sec)






[8.0.27 127.0.0.1:3380]>select * from t1 join t2 on t1.b=t2.b;
......
+------+------+------+------+------+------+
500 rows in set (0.02 sec)

從執行邏輯和執行結果上,都印證了Hash Join必然會比Block Nested-Loop Join要好。所以,在MySQL 8.0版本,Block Nested-Loop Join將不復存在,所有原先使用其算法的表關聯SQL,最終都會被優化成選擇Hash Join進行表關聯。

4、Index Nested-Loop Join

前面提到的 Block Nested-Loop Join 和 Hash Join,都是MySQL自己內部實現的優化,如果沒有其他更好的算法,那么基于這兩種算法基礎上的表關聯慢SQL,人為干預改進的可能性,是不是就微無其微了。

我們仔細分析一下前面這兩種算法的特點,Block Nested-Loop Join 的改進是降低了表掃描次數, Hash Join的改進是降低了數據對比的次數,但他兩,依然有一個致命的共同點,如果被驅動表足夠大(大表)時,比如有N億數據量,那么,哪怕掃描一次被驅動表,也會引起數據庫性能急劇下降。

知道了問題在哪,自然就有了優化的方向。設想一下,如果被驅動表的關聯列,像Hash Join中的哈希表一樣,存在索引,會是個什么情況呢?

圖片圖片

驅動表中的每一行記錄,都可以通過被驅動表的索引列,進行索引查找(與關聯列有關,可以是主鍵,也可以是二級索引),這瞬間就解決了被驅動表被掃描的問題。其本質,和單表查詢中,通過建立合適索引的方式進行優化,是不是很相似。哪怕驅動表再大,如果索引列每個鍵值對應的數據量不大,那么索引查找速度依然可以快到起飛,這算法就叫 Index Nested-Loop Join。

先前咱兩個測試表中,a列和b列數據是一樣的,a列有索引,b列無索引,所以,咱將測試SQL變通一下

select * from t1 join t2 on t1.b=t2.b;
# 替換為
select * from t1 join t2 on t1.b=t2.a;

執行計劃:

[5.7.37-log localhost:mysql.sock]>explain select * from t1 join t2 on t1.b=t2.a\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 100.00
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
   partitions: NULL
         type: ref
possible_keys: idx_a
          key: idx_a
      key_len: 5
          ref: db1.t1.b
         rows: 1
     filtered: 100.00
        Extra: NULL
2 rows in set, 1 warning (0.00 sec)

執行速度:

[5.7.37-log localhost:mysql.sock]>select * from t1 join t2 on t1.b=t2.a;
......
+------+------+------+------+------+------+
500 rows in set (0.01 sec)

你是不是在疑惑,看這執行速度,和Hash Join差別也不大,那是因為咱的被驅動表t2數據量太少,隨著測試數據量的增大,差距會越來越明顯。

四、優化思路

前面的測試SQL,相對來講,簡化的有點過于簡單了,實際應用中,必然會有一大堆查詢條件跟在其后,那這一堆查詢條件,在進行SQL優化時,會不會對你造成干擾呢?

1、初始SQL

測試SQL做個變化,讓其他稍微貼近實際情況:

select *
from t1 join t2 on t1.b = t2.b
where
    t1.c in (6, 12, 18, 24, 30)
    and t2.c in (6, 12, 18, 24, 30);

執行計劃:

[5.7.37-log localhost:mysql.sock]>explain select *
    -> from t1 join t2 on t1.b = t2.b
    -> where
    ->     t1.c in (6, 12, 18, 24, 30)
    ->     and t2.c in (6, 12, 18, 24, 30)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 50.00
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 100345
     filtered: 5.00
        Extra: Using where; Using join buffer (Block Nested Loop)
2 rows in set, 1 warning (0.00 sec)

從上面的執行計劃可以看到,t1表較小為驅動表,t2表較大為被驅動表。咱一步一步分析,暫時剔除t2表,先看t1表是否有優化的空間,其現在是全表掃描,并通過t1.c列進行數據過濾。單表查詢,如果查詢條件列有索引,必然會加快查詢速度對吧。

2、SQL優化1

t1表中,a、b、c列數據是一樣的,a列有索引,所以咱不額外創建索引了,直接使用a列替代c列,重寫測試SQL:

select *
from t1 join t2 on t1.b = t2.b
where
    t1.a in (6, 12, 18, 24, 30)
    and t2.c in (6, 12, 18, 24, 30);

查看新的執行計劃:

[5.7.37-log localhost:mysql.sock]>explain select *
    -> from t1 join t2 on t1.b = t2.b
    -> where
    ->     t1.a in (6, 12, 18, 24, 30)
    ->     and t2.c in (6, 12, 18, 24, 30)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: range
possible_keys: idx_a
          key: idx_a
      key_len: 5
          ref: NULL
         rows: 5
     filtered: 100.00
        Extra: Using index condition
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 100345
     filtered: 5.00
        Extra: Using where; Using join buffer (Block Nested Loop)
2 rows in set, 1 warning (0.00 sec)

t1表從原先的全表掃描,變成了索引查找,預估讀取的數據行,也從原來的1000行變成了5行,優化效果明顯。此時,再看看t2表,因為關聯列t2.b沒有索引,查詢列t2.c也沒有索引,所以t2表是掃描一次后,通過Block Nested-Loop Join算法與Join Buffer中的數據進行匹配。

在前面講解Index Nested-Loop Join時,咱知道,如果關聯列 t2.b 有索引,就會使用Index Nested-Loop Join算法進行數據匹配,那,如果關聯列沒索引,但是查詢過濾列 t2.c 有索引,會是怎樣的?

3、SQL優化2

同樣的,咱用 t2.a 列替代 t2.c 列,重寫測試SQL:

select *
from t1 join t2 on t1.b = t2.b
where
    t1.a in (6, 12, 18, 24, 30)
    and t2.a in (6, 12, 18, 24, 30);

執行計劃:

[5.7.37-log localhost:mysql.sock]>explain select *
    -> from t1 join t2 on t1.b = t2.b
    -> where
    ->     t1.a in (6, 12, 18, 24, 30)
    ->     and t2.a in (6, 12, 18, 24, 30)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: range
possible_keys: idx_a
          key: idx_a
      key_len: 5
          ref: NULL
         rows: 5
     filtered: 100.00
        Extra: Using index condition
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
   partitions: NULL
         type: range
possible_keys: idx_a
          key: idx_a
      key_len: 5
          ref: NULL
         rows: 5
     filtered: 10.00
        Extra: Using index condition; Using where; Using join buffer (Block Nested Loop)
2 rows in set, 1 warning (0.00 sec)

與前面的執行計劃對比發現,其依然是使用Block Nested-Loop Join算法,只不過原先t2表,從全表掃描,變成了通過 t2.a 列索引,一次性查找出全部數據后,再與Join Buffer中t1表的結果集進行匹配,如果 t2.a 列根據查詢條件過濾出來的數據,足夠少,這也不失為一個較好的優化思路。

4、SQL優化3

當然了,如果關聯列有索引,查詢列沒索引,你已經知道了是使用Index Nested-Loop Join算法,繼續重寫測試SQL:

select *
from t1 join t2 on t1.b = t2.a
where
    t1.a in (6, 12, 18, 24, 30)
    and t2.c in (6, 12, 18, 24, 30);

執行計劃:

[5.7.37-log localhost:mysql.sock]>explain select *
    -> from t1 join t2 on t1.b = t2.a
    -> where
    ->     t1.a in (6, 12, 18, 24, 30)
    ->     and t2.c in (6, 12, 18, 24, 30)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: range
possible_keys: idx_a
          key: idx_a
      key_len: 5
          ref: NULL
         rows: 5
     filtered: 100.00
        Extra: Using index condition; Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
   partitions: NULL
         type: ref
possible_keys: idx_a
          key: idx_a
      key_len: 5
          ref: db1.t1.b
         rows: 1
     filtered: 50.00
        Extra: Using where
2 rows in set, 1 warning (0.00 sec)

被驅動表關聯列有索引,查詢列無索引,使用Index Nested-Loop Join算法。

5、疑問

如果t2表中,關聯列和查詢列,都有索引,他會怎么選?為了更好的比較,咱給 t2.c 列創建一個索引,并對 t2.a 列的數據進行適當的調整。

# 添加c列索引
alter table t2 add index idx_c(c);


# 調整t2表a列數據,a列查詢條件中的值,每個值對應的數據量為4000
update t2 set a=a%50;


# 消除表碎片,避免被其干擾
alter table t2 engine=innodb;


# 驅動表傳過來的鍵值,每個鍵值對應的數據為4000行
[5.7.37-log localhost:mysql.sock]>select a,count(a) cnt
    -> from t2
    -> where a in (6, 12, 18, 24, 30)
    -> group by a;
+------+------+
| a    | cnt  |
+------+------+
|    6 | 4000 |
|   12 | 4000 |
|   18 | 4000 |
|   24 | 4000 |
|   30 | 4000 |
+------+------+
5 rows in set (0.01 sec)




# 總共符合條件的數據,5行
[5.7.37-log localhost:mysql.sock]>select * from t2 where c in (6, 12, 18, 24, 30);
+----+------+------+------+
| id | a    | b    | c    |
+----+------+------+------+
|  3 |    6 |    6 |    6 |
|  6 |   12 |   12 |   12 |
|  9 |   18 |   18 |   18 |
| 12 |   24 |   24 |   24 |
| 15 |   30 |   30 |   30 |
+----+------+------+------+
5 rows in set (0.01 sec)

重寫測試SQL:

select *
from t1 join t2 on t1.b = t2.a
where
    t1.a in (6, 12, 18, 24, 30)
    and t2.c in (6, 12, 18, 24, 30);

執行計劃:

[5.7.37-log localhost:mysql.sock]>explain select *
    -> from t1 join t2 on t1.b = t2.a
    -> where
    ->     t1.a in (6, 12, 18, 24, 30)
    ->     and t2.c in (6, 12, 18, 24, 30)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: range
possible_keys: idx_a
          key: idx_a
      key_len: 5
          ref: NULL
         rows: 5
     filtered: 100.00
        Extra: Using index condition
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: t2
   partitions: NULL
         type: range
possible_keys: idx_a,idx_c
          key: idx_c
      key_len: 5
          ref: NULL
         rows: 5
     filtered: 4.55
        Extra: Using index condition; Using where; Using join buffer (Block Nested Loop)
2 rows in set, 1 warning (0.00 sec)

由此可見,Block Nested-Loop Join (Hash Join)與 Index Nested-Loop Join 對比,并沒有哪一種算法更優一說,只要其整體成本比另一種低,那他就是最合適的。當然了,前面所有例子,都是只有2個表關聯,對于3表及以上的關聯SQL而言,如果你把前2個表的關聯結果,當成一個新的驅動表看待,那么所有后面的表關聯,是不是都只需分析兩表關聯的情況即可。

五、最后

至此,對于想學習SQL優化的你,功力是不是又有長進了。如果你還有其他疑問,可以寫在評論區,咱后面再繼續探討。

責任編輯:武曉燕 來源: 京東云開發者
相關推薦

2022-07-15 13:01:13

Kotlin編程語言Java

2019-04-28 16:10:50

設計Redux前端

2020-02-04 09:53:05

數據安全數據泄漏信息安全

2015-05-05 11:04:31

CoreOS自動化運維

2019-10-08 09:29:41

架構代碼業務邏輯

2013-09-16 16:01:23

Android開發代碼

2017-09-06 15:54:14

2012-04-29 10:37:28

APP

2010-07-16 09:00:20

開源RedOffice紅旗2000

2020-11-19 10:09:55

漏洞逆向角度證書覆蓋

2019-11-27 10:11:22

勒索病毒網絡安全

2025-11-05 03:00:00

Linux內核TCP粘包

2021-10-14 08:58:48

Java冒泡排序

2013-12-11 21:48:38

OpenStack

2014-07-14 15:19:43

IT信息工程運維

2009-07-08 19:44:56

2018-07-26 07:21:12

2012-10-26 11:12:22

WOT云計算架構師

2017-11-20 16:17:50

智慧城市

2022-09-11 15:12:04

MySQL數據庫優化器
點贊
收藏

51CTO技術棧公眾號

不卡视频一区二区三区| 亚洲福利视频在线| 最新国产精品久久| www.狠狠干| 国产美女一区| 色777狠狠综合秋免鲁丝| 深爱五月综合网| 伊人久久视频| 一区二区三区四区激情| 麻豆精品传媒视频| 99国产精品久久久久久久成人| 怡红院精品视频在线观看极品| 亚洲欧洲日本专区| 在线免费观看av网| 69av成人| 亚洲欧美在线高清| 欧美日韩亚洲一区二区三区四区| 国产黄色大片网站| 久久国产毛片| 欧美国产在线视频| 99久久99久久精品免费| 国产香蕉精品| 欧美浪妇xxxx高跟鞋交| 久久美女福利视频| 在线你懂的视频| 欧美极品少妇xxxxⅹ高跟鞋| 国产精品一级久久久| 亚洲性在线观看| 狂野欧美性猛交xxxx巴西| 九九九热精品免费视频观看网站| 人妻视频一区二区| 欧美人妖在线观看| 日韩精品在线一区| 亚洲一区二区三区观看| 成人日韩在线| 一本到一区二区三区| 精品成在人线av无码免费看| 韩国中文字幕在线| 国产精品污污网站在线观看| 欧美二区三区在线| 天天干,夜夜爽| 粉嫩在线一区二区三区视频| 92看片淫黄大片欧美看国产片 | 刘亦菲毛片一区二区三区| 免费精品99久久国产综合精品| 日韩美女视频中文字幕| 久久露脸国语精品国产91| 一区二区三区网站| 精品国产一区久久久| 一本在线免费视频| 色无极亚洲影院| 最好看的2019的中文字幕视频| 中文字幕在线观看网址| 久久精品66| 亚洲第一视频在线观看| 久久免费精品国产| 99ri日韩精品视频| 亚洲成年人在线播放| 男人添女人荫蒂国产| 久久av偷拍| 日韩欧美国产综合| 亚洲熟女一区二区三区| av不卡一区二区| 日韩欧美成人午夜| 国产艳妇疯狂做爰视频| xxxx日韩| 亚洲精品久久久久久久久久久久| 少妇饥渴放荡91麻豆| 亚洲国产国产| 一区二区欧美亚洲| 日本黄色录像视频| 午夜精品久久99蜜桃的功能介绍| 欧美xxxx综合视频| 久久精品国产亚洲av麻豆色欲| 亚洲视频观看| 国产91精品久久久久| 在线精品免费视| 欧美aaa在线| 亚洲一区二区三区sesese| www.四虎在线观看| 99精品视频一区二区三区| 欧美国产二区| 美女免费久久| 婷婷开心激情综合| av在线无限看| 91精品啪在线观看国产手机| 日韩精品亚洲精品| 久久人妻无码aⅴ毛片a片app| 欧美日韩综合| 国产精品电影观看| 国产三级第一页| 99久久久无码国产精品| 天天综合狠狠精品| 婷婷在线播放| 日本韩国欧美一区| 年下总裁被打光屁股sp | 欧美国产大片| 制服丝袜亚洲网站| 少妇毛片一区二区三区| 久久影视一区| 51色欧美片视频在线观看| 中文在线免费观看| 丁香婷婷综合激情五月色| 欧美一区二区三区四区在线观看地址 | 精品视频一区在线视频| 久草福利资源在线| 国产欧美综合一区二区三区| 国产在线视频2019最新视频| 视频在线观看你懂的| 亚洲人成7777| 可以免费观看av毛片| 精品视频一二| 伊人久久精品视频| 日韩欧美三级在线观看| 久久精品国产99久久6| 久久国产日韩欧美| 成人福利在线观看视频| 在线看国产日韩| 国产 xxxx| 91精品国产91久久综合| 日韩美女免费线视频| 亚洲国产精品一| 亚洲欧美在线视频观看| jizz欧美激情18| 亚洲人挤奶视频| 91国偷自产一区二区三区的观看方式| 国产精品午夜福利| 国产欧美精品一区二区色综合| 99在线精品免费视频| 激情视频亚洲| 日韩视频精品在线| 中文无码av一区二区三区| 91在线国内视频| 国产天堂视频在线观看| 欧美三级一区| 麻豆乱码国产一区二区三区| wwwwww在线观看| 国产亚洲女人久久久久毛片| 国产91在线免费| 四虎5151久久欧美毛片| 久久久综合av| 亚洲欧美激情另类| 一区二区三区在线免费视频| 婷婷激情综合五月天| 色喇叭免费久久综合| 国产精品免费在线免费 | 亚洲在线视频播放| 欧美国产精品一区二区三区| 热久久精品国产| 国产免费播放一区二区| 国产不卡av在线免费观看| 天天影院图片亚洲| 色成人在线视频| 美女被到爽高潮视频| 久久久亚洲人| 天堂精品一区二区三区| 四虎影视成人精品国库在线观看| 色小说视频一区| 99国产精品一区二区三区| 亚洲美女偷拍久久| 日批视频免费看| 国产欧美欧美| 日本高清一区| 成人av在线播放| 欧美裸体xxxx极品少妇| 风流老熟女一区二区三区| 亚洲国产一区二区三区| 亚洲中文字幕一区| 六月婷婷一区| 亚洲视频电影| 99re8这里有精品热视频8在线| 91av视频在线播放| av中文字幕一区二区三区| 欧美精品第一页| 久久精品国产亚洲av麻豆色欲| aaa国产一区| 亚洲视频在线a| 亚洲欧美在线专区| 国产综合欧美在线看| 久久久人成影片一区二区三区在哪下载 | 中文日本在线观看| 91精品国产综合久久福利软件| 欧美成人手机视频| 95精品视频在线| 国产一级片自拍| 亚洲高清av| 先锋影音亚洲资源| 91综合精品国产丝袜长腿久久| 97人人模人人爽人人喊中文字| 黄视频在线播放| 欧美一区二区三区视频| 天天综合网入口| 亚洲欧洲另类国产综合| 亚洲国产精品成人综合久久久| 美腿丝袜亚洲综合| 日b视频免费观看| 成人精品天堂一区二区三区| 岛国视频一区| 国产精品一区二区免费福利视频| 欧美精品videossex88| 黄色网址在线播放| 欧美成人精品3d动漫h| 人人妻人人爽人人澡人人精品| 亚洲精品视频自拍| 国产精品亚洲无码| 国产成人午夜精品5599| 国产免费人做人爱午夜视频| 欧美欧美天天天天操| 亚洲高清不卡一区| 色88888久久久久久影院| 91精品啪aⅴ在线观看国产| 乡村艳史在线观看| 欧美情侣性视频| 幼a在线观看| 国产午夜精品久久久 | 亚洲日本中文字幕| 成人午夜视频一区二区播放| 欧美日韩视频在线观看一区二区三区| 国产网站在线看| 亚洲女人小视频在线观看| 2019男人天堂| 91免费国产视频网站| 无码人妻久久一区二区三区蜜桃| 久久99精品久久只有精品| 久久精品网站视频| 国产偷自视频区视频一区二区| 奇米777四色影视在线看| 色97色成人| 亚洲三区在线| 成人av国产| 欧美日韩系列| 亚洲尤物av| 免费久久久一本精品久久区| 高清一区二区三区| 91精品国产高清久久久久久91裸体 | 亚洲欧美色视频| 亚洲国产精品久久精品怡红院| 亚洲精华国产精华精华液网站| 欧美一区永久视频免费观看| 中文字幕网址在线| 欧美体内she精视频| 国产成人精品777777| 欧美日韩中文字幕在线| 日韩精品一区二区三区国语自制| 亚洲最快最全在线视频| 青娱乐国产盛宴| 一区二区三区欧美亚洲| 免费在线观看h片| 伊人婷婷欧美激情| 麻豆chinese极品少妇| 亚洲精品中文在线影院| 亚洲熟女www一区二区三区| 一区二区视频免费在线观看| 国产午夜手机精彩视频| 亚洲黄一区二区三区| 欧美色图一区二区| 亚洲一区二区免费视频| 久久久久久久福利| 午夜精品久久久久久久久| 自拍偷拍欧美亚洲| 福利一区福利二区微拍刺激| 亚洲午夜18毛片在线看| 欧美性xxxx在线播放| 中国女人真人一级毛片| 欧美精品久久天天躁| www.狠狠干| 日韩国产欧美区| 成年人在线免费观看| 日韩视频亚洲视频| 日本aa在线| 热99在线视频| 国产亚洲人成a在线v网站 | 国产综合免费视频| 日韩av在线发布| 中国黄色片一级| 成人黄色在线网站| 亚洲精品国产91| 综合中文字幕亚洲| 国产精品黄色网| 在线观看免费视频综合| 国产又粗又猛视频免费| 欧美成人video| 美国一级片在线免费观看视频| 色吧影院999| sqte在线播放| 国产精品日韩av| 91九色鹿精品国产综合久久香蕉| 久99久在线| 999久久久精品国产| 欧美人成在线观看| 日本女人一区二区三区| 佐佐木明希电影| 中文文精品字幕一区二区| 久久综合色综合| 欧美另类一区二区三区| 五月天丁香视频| xxxxx91麻豆| 韩日精品一区二区| 亚洲影院在线看| 奇米色欧美一区二区三区| 熟女熟妇伦久久影院毛片一区二区| 亚洲精品一级| 中文 日韩 欧美| 国产三级欧美三级| 欧美日韩激情在线观看| 欧美视频在线一区| 五十路在线观看| 欧美国产日韩一区二区| 97精品国产99久久久久久免费| 99在线看视频| 日韩久久视频| 国产精品99久久免费黑人人妻| 国产寡妇亲子伦一区二区| 欧美熟妇激情一区二区三区| 亚洲18色成人| 精品人妻av一区二区三区| 在线亚洲欧美视频| 中文一区一区三区高中清不卡免费| 91福利入口| 香蕉久久网站| www.99av.com| 久久久美女毛片| 成人免费看片98欧美| 精品国产亚洲在线| 久操视频在线| 国产日韩欧美黄色| 色乱码一区二区三区网站| 日韩毛片在线免费看| 91亚洲国产成人精品一区二三| 欧美日韩一级大片| 91精品国产一区二区人妖| 国产裸舞福利在线视频合集| 欧美亚洲视频在线观看| 国产精品毛片av| 国产精品一色哟哟| 国产成人亚洲精品青草天美| 欧美做爰爽爽爽爽爽爽| 欧美日本乱大交xxxxx| 在线免费看黄网站| 国产精品人成电影| 欧美激情黄色片| 亚洲美女爱爱视频| 日韩一区在线免费观看| 中文字幕一区二区三区免费看| 中文字幕亚洲一区在线观看| 日本精品网站| 在线不卡日本| 激情av综合网| 真实国产乱子伦对白在线| 日韩视频免费观看高清完整版 | 日本高清视频在线播放| 国产精品一区二区三区在线播放| 精品freesex老太交| 亚洲36d大奶网| 亚洲天堂av一区| 国产人妻精品一区二区三| 欧美大荫蒂xxx| 日韩mv欧美mv国产网站| 99热成人精品热久久66| 国产亚洲一区二区三区在线观看 | 亚洲精品美女久久7777777| 七七婷婷婷婷精品国产| 中文国语毛片高清视频| 日韩一级片在线观看| 暧暧视频在线免费观看| 精品视频免费观看| 三级影片在线观看欧美日韩一区二区| 日本污视频网站| 日韩视频免费直播| 中文字幕乱码在线播放| 日韩视频专区| 国产呦精品一区二区三区网站| 精品少妇久久久久久888优播| 日韩精品中文字幕视频在线| 成人亚洲综合| www.亚洲成人网| 久久久久9999亚洲精品| 91精品国产乱码久久久| 欧美极品少妇xxxxx| 亚洲自拍电影| 少妇性l交大片7724com| 精品久久久久久久久久久久久| 国产高清自拍视频在线观看| 92福利视频午夜1000合集在线观看| 在线日韩视频| 男女男精品视频网站| 亚洲高清在线观看| 精品123区| 精品无码一区二区三区爱欲| 国产色综合一区| 欧美特级特黄aaaaaa在线看| 国产成人av在线播放| 欧美黄在线观看| caopeng视频| 精品三级在线观看| japanese23hdxxxx日韩| 男人插女人视频在线观看| 中文无字幕一区二区三区 | 亚洲日本va| 人人干人人干人人|