国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

聊一聊 MySQL 相關子查詢

數據庫 MySQL
這一篇我們就來聊聊不相關子查詢轉換為相關子查詢,以及相關子查詢執行的那些事。

子查詢系列的上一篇文章??《MySQL 不相關子查詢怎么執行?》???提到過,MySQL 有可能把不相關?子查詢轉換為相關子查詢。

這一篇我們就來聊聊不相關子查詢轉換為相關子查詢,以及相關子查詢執行的那些事。

本文不相關子查詢都是指的 IN 子查詢,內容基于 MySQL 8.0.29 源碼。

正文

1、explain type、ref 列的顯示邏輯

本文示例 SQL 中的表,都來自于官方提供的測試數據庫 sakila,下載鏈接如下:https://downloads.mysql.com/docs/sakila-db.tar.gz

相關子查詢有兩種來源(也許還有其它來源?):

  • 一種是我們純手工打造的。
  • 另一種就是從不相關子查詢轉換來的了。

通過 explain 查看這兩種 SQL 的執行計劃,子查詢的 type、ref 列可能一樣,也可能不一樣,難免讓人困惑。

我們先來弄清楚兩種 SQL 的 explain 結果中,子查詢的 type、ref 列為什么會顯示不一樣?

示例 SQL 1:

-- 為了保證 EXISTS 子查詢不會轉換為半連接
-- 先把半連接優化關閉
SET optimizer_switch="semijoin=off";

-- 純手工打造的相關子查詢
EXPLAIN SELECT * FROM city
WHERE city_id < 100 AND EXISTS (
SELECT city_id FROM address
WHERE city.city_id = address.city_id
)

-- explain 結果如下,為了方便查看
-- 我調整了 ref 列的位置
-- 并且刪掉了 partitions 列
+----+--------------------+---------+-------+---------------------+----------------+----------------+---------+------+----------+-------------+
| id | select_type | table | type | ref | possible_keys | key | key_len | rows | filtered | Extra |
+----+--------------------+---------+-------+---------------------+----------------+----------------+---------+------+----------+-------------+
| 1 | PRIMARY | city | range | <null> | PRIMARY | PRIMARY | 2 | 99 | 100.0 | Using where |
| 2 | DEPENDENT SUBQUERY | address | ref | sakila.city.city_id | idx_fk_city_id | idx_fk_city_id | 2 | 1 | 100.0 | Using index |
+----+--------------------+---------+-------+---------------------+----------------+----------------+---------+------+----------+-------------+

子查詢 type 列的值為 ref,表示 address 表使用 idx_fk_city_id 索引(key 列的值)進行等值范圍掃描。

子查詢 ref 列的值為 sakila.city.city_id,表示 where 條件中 address.city_id 字段值來源于主查詢 city 表的 city_id 字段值。

示例 SQL 2:

-- 為了保證 IN 子查詢不會轉換為半連接
-- 先把半連接優化關閉
SET optimizer_switch="semijoin=off";

-- 不相關子查詢
EXPLAIN SELECT * FROM city
WHERE city_id < 100 AND city_id IN (
SELECT city_id FROM address
)

-- explain 結果如下
-- 可以看到不相關子查詢已經轉換為相關子查詢了
-- 為了方便查看,我調整了 ref 列的位置
-- 并且刪掉了 partitions 列
+----+--------------------+---------+----------------+--------+----------------+----------------+---------+------+----------+-------------+
| id | select_type | table | type | ref | possible_keys | key | key_len | rows | filtered | Extra |
+----+--------------------+---------+----------------+--------+----------------+----------------+---------+------+----------+-------------+
| 1 | PRIMARY | city | range | <null> | PRIMARY | PRIMARY | 2 | 99 | 100.0 | Using where |
| 2 | DEPENDENT SUBQUERY | address | index_subquery | func | idx_fk_city_id | idx_fk_city_id | 2 | 1 | 100.0 | Using index |
+----+--------------------+---------+----------------+--------+----------------+----------------+---------+------+----------+-------------+

子查詢 type 列的值為 index_subquery,ref 列的值為 func。

這 2 列的值看起來挺唬人的,但實際上和示例 SQL 1 的 type = ref,ref = sakila.city.city_id 并沒有什么不一樣,無非是換了一身行頭而已。

我們先從源碼里看看 type = index_subquery 是怎么來的:

// sql/opt_explain.cc
bool Explain_join::explain_join_type(){
const join_type j_t = type == JT_UNKNOWN ? JT_ALL : type;
const char *str = join_type_str[j_t];
// 訪問方式是 eq_ref
if ((j_t == JT_EQ_REF ||
// 訪問方式是 ref
j_t == JT_REF ||
// 訪問方式是 ref_or_null
j_t == JT_REF_OR_NULL) &&
// 當前 select 語句是子查詢
join->query_expression()->item) {
/*
For backward-compatibility, we have special presentation of "index
lookup used for in(subquery)": we do not show "ref/etc", but
"index_subquery/unique_subquery".
*/
// 如果這個 if 判斷條件成立
// 就說明 IN 子查詢已經轉換為【相關子查詢】了
if (join->query_expression()->item->engine_type() ==
Item_subselect::INDEXSUBQUERY_ENGINE)
str = (j_t == JT_EQ_REF)
? "unique_subquery"
: "index_subquery";
}

fmt->entry()->col_join_type.set_const(str);
return false;
}

上面代碼是 explain 結果中 type 列的顯示邏輯。

從代碼可以看到 IN 子查詢轉換為相關子查詢之后,type 列的顯示邏輯如下:

  • 表的訪問方式是eq_ref,type 列的值為 unique_subquery。
  • 表的訪問方式是ref 或 ref_or_null,type 列的值為 index_subquery。

由此,我們就揭開了 index_subquery 的神秘面紗,實際上它就是 ref 或 ref_no_null。

另外,從代碼的英文注釋中,我們可以看到,type 列之所以這么顯示是為了向后兼容。

接下來,我們再來看看 ref 列的顯示邏輯:

// sql/sql_select.h
class store_key {
......
virtual const char *name() const {
// Compatible with legacy behavior.
// where 條件字段是正常字段(另一個表的字段)
// 返回的是字段全名,即 db.table.field
if (item->type() == Item::FIELD_ITEM) {
return item->full_name();
} else {
return "func";
}
}
......
}

IN 子查詢轉換為相關子查詢之后,主查詢 where 條件的 city_id 字段和子查詢 select 子句的 city_id 字段會組成新條件(address.city_id = city.city_id),附加到子查詢 where 條件中。

新條件的 city.city_id 字段類型是 REF_ITEM,而不是 FIELD_ITEM,在調試控制臺執行如下命令可以驗證:

這里 REF_ITEM 是對 FIELD_ITEM 的引用,這是源碼中對包含子查詢的 IN 條件字段所做的優化,我們在此不深入具體細節。

# 新條件 city.city_id 字段的表名
(lldb) print ((Item_field *)((Item_cache_int *)item->real_item())->get_example())->table_name
(const char *) $16 = "city"
# 新條件 city.city_id 字段的字段名
(lldb) print ((Item_field *)((Item_cache_int *)item->real_item())->get_example())->field_name
(const char *) $17 = "city_id"
# 新條件 city.city_id 的類型
(lldb) print item->type()
(Item::Type) $18 = REF_ITEM

所以,新條件類型是 REF_ITEM,命中了前面代碼中的 else 分支(return "func"),explain 結果的 ref 列就顯示為 func 了。

ref 列的值雖然顯示為 func,但是新條件 city.city_id 字段還是讀取的主查詢 city_id 字段值,只不過是中間隔了一層,其它并沒有什么特殊的。

圖片

厘清了兩種 SQL explain 結果 type、ref 列的不同之處,就可以開始介紹不相關子查詢轉換為相關子查詢的邏輯了。

因為在介紹過程中會用到 optimizer trace,所以先來簡單了解下 optimizer trace 的相關知識點。

2、optimizer trace

通過 optimizer trace,我們可以了解到 MySQL 準備階段、優化階段、執行階段的一些內部細節。特別是可以了解 MySQL 選擇某個執行計劃的決策依據。

optimizer trace 默認為關閉狀態,如果需要,可以通過執行以下 SQL 開啟:

SET optimizer_trace = "enabled=on"

開啟了 optimizer trace,執行 SQL 語句之后,可以通過以下 SQL 得到 optimizer trace 結果:

SELECT * FROM information_schema.OPTIMIZER_TRACE

OPTIMIZER_TRACE 表有 4 個字段:

  • QUERY:SQL 語句。
  • TRACE:json 格式的 optimizer trace 內容,如果內容長度超過系統變量 optimizer_trace_max_mem_size 的值就會被截斷。該系統變量控制的是一條 SQL 的 optimizer trace 內容長度,默認值是 1048576(字節)。
  • MISSING_BYTES_BEYOND_MAX_MEM_SIZE:如果 optimizer trace 內容因超長被截斷,這個字段記錄了被截斷的字節數。
  • INSUFFICIENT_PRIVILEGES:如果用戶執行 QUERY 字段中的 SQL 語句權限不夠,導致 TRACE 字段內容為空,該字段會顯示為 1。

如果使用客戶端(如 Navicat),我們執行一條 SQL,客戶端可能會額外執行一些統計 SQL。

因為默認配置只會保留最近一條 SQL 的 optimizer trace 內容,使用客戶端有可能導致我們看不到自己的 SQL optimizer trace 內容。

這種情況下,我們需要修改 2 個系統變量的值:

  • optimizer_trace_offset:從最近執行的哪條 SQL 開始保存 optimizer trace 內容,默認值為 -1,表示從最近執行的 1 條 SQL 開始保存 optimizer trace 內容。
  • optimizer_trace_limit:保存多少條 optimizer trace 內容,默認值為 1。

圖片

3、IN 子查詢轉換

IN 子查詢有 3 大執行策略:

  • 轉換為半連接,這是最優先的執行策略。
  • 子查詢物化。
  • 轉換為相關子查詢。

如果子查詢中存在像 group by 子句這樣的限制因素,或者因為成本問題不能轉換為半連接,那就要在物化和相關子查詢兩種策略中二選一了。

(1)要不要轉換?

還是以前面的 IN 子查詢 SQL 為例,我們通過 optimizer trace 來看看 MySQL 在物化和相關子查詢兩種策略中二選一的過程。

-- 為了保證 IN 子查詢不會轉換為半連接
-- 先把半連接優化關閉
SET optimizer_switch="semijoin=off";

-- 開啟 optimizer trace
SET optimizer_trace = "enabled=on";

-- 執行 select 語句
SELECT * FROM city
WHERE city_id < 100 AND city_id IN (
SELECT city_id FROM address
);

-- 獲取 select 語句的跟蹤信息
SELECT * FROM information_schema.OPTIMIZER_TRACE;

以下是 optimizer trace 中關于物化和相關子查詢兩種策略的決策依據:

{
"execution_plan_for_potential_materialization": {
"subq_mat_decision": {
"parent_fanouts": [
{
"select#": 1,
"subq_attached_to_table": true,
"table": "`city`",
"fanout": 99,
"cacheable": true
}
],
"cost_to_create_and_fill_materialized_table": 123.849,
"cost_of_one_EXISTS": 0.349669,
"number_of_subquery_evaluations": 99,
"cost_of_materialization": 133.749,
"cost_of_EXISTS": 34.6172,
"chosen": false
}
}
}

chosen 字段值為 false?,表示 MySQL 沒有?使用物化方式執行子查詢,原因是使用物化方式的成本(cost_of_materialization = 133.749?)比相關子查詢的成本(cost_of_EXISTS = 34.6172)更高。

知道了結果,我們再來看看物化和相關子查詢的成本是怎么計算的。

使用物化方式執行子查詢的成本:

parent_fanouts.fanout = 99 表示預估的主查詢 city 表中滿足 city_id < 100 的記錄數量。

number_of_subquery_evaluations 表示子查詢的執行次數?,因為對于主查詢中滿足 city_id < 100 的每一條記錄,相關子查詢都要執行一次,所以,這個字段值等于 parent_fanouts.fanout。

cost_to_create_and_fill_materialized_table 表示創建臨時表的成本,加上把子查詢中的所有記錄都寫入臨時表的成本。

cost_of_materialization 表示使用物化方式執行 IN 子查詢的總成本,計算邏輯如下:cost_of_materialization = ?cost_to_create_and_fill_materialized_table?(123.849) + number_of_subquery_evaluations(99) * 0.1 = 133.749。

其中 0.1 是從主查詢中讀取一條記錄之后,拿到 city_id 字段值,去臨時表中查詢記錄的成本常數,可以通過以下 SQL 獲取:

SELECT
cost_name, cost_value, default_value
FROM mysql.server_cost
WHERE cost_name = 'memory_temptable_row_cost'

+---------------------------+------------+---------------+
| cost_name | cost_value | default_value |
+---------------------------+------------+---------------+
| memory_temptable_row_cost | <null> | 0.1 |
+---------------------------+------------+---------------+

查詢 cost_name 等于 memory_temptable_row_cost 的成本常數,因為使用的是內存臨時表。

如果子查詢使用的是磁盤臨時表,則需要查詢 cost_name 等于 disk_temptable_row_cost 的成本常數。

轉換為相關子查詢的執行成本:cost_of_EXISTS = ?cost_of_one_EXISTS?(0.349669) * number_of_subquery_evaluations(99) = 34.6172。

cost_of_one_EXISTS 表示子查詢執行一次的成本,number_of_subquery_evaluations 表示子查詢的執行次數。

(2)怎么轉換?

還是以前面的示例 SQL 為例:

SELECT * FROM city
WHERE city_id < 100 AND city_id IN (
SELECT city_id FROM address
)

在查詢準備階段,還沒有確定子查詢的執行策略之前,就會把主查詢 where 條件中的 IN 條件字段和子查詢 select 子句中的字段組成新條件,并附加到子查詢的 where 條件中。

也就是把 city 表的 city_id 字段和 address 表的 city_id 字段組成新條件,附加到子查詢中,看起來就像是這樣的 select 語句:

SELECT * FROM city
WHERE city_id < 100 AND EXISTS (
SELECT city_id FROM address
WHERE city.city_id = address.city_id
)

那么問題來了,如果查詢優化階段決定 IN 子查詢不轉換為相關子查詢,附加到子查詢 where 條件中的新條件怎么辦?

這個好辦,再刪掉就是了。

在構造的時候,新條件會被打上標記,表示這個條件是 IN 子查詢轉換為相關子查詢時新構造的。

有了這個標記,就能知道要刪除子查詢 where 條件中的那個條件了。

4、執行流程

不管是 IN 子查詢轉換來的,還是我們純手工打造的相關子查詢,到了執行階段,流程就一樣了。

還是以前面的示例 SQL 1 為例,來介紹相關子查詢的主要執行流程:

SELECT * FROM city
WHERE city_id < 100 AND EXISTS (
SELECT city_id FROM address
WHERE city.city_id = address.city_id
)

步驟 1,主查詢從 city 表讀取一條記錄。

步驟 2,判斷主查詢記錄是否匹配 where 條件。

因為 city_id < 100 在前,先判斷主查詢記錄是否滿足這個條件。

如果滿足,則執行子查詢,否則,回到步驟 1。

假設主查詢讀取到 city 表的 city_id 字段值為 8,此時,要執行的子查詢就是這樣的了:

SELECT city_id FROM address
WHERE address.city_id = 8

如果執行子查詢查到了記錄,說明主查詢記錄滿足 city_id < 100 和 EXISTS 子查詢兩個條件,把主查詢記錄返回給客戶端,否則,回到步驟 1。

重復執行步驟 1 ~ 2,直到讀完主查詢 city 表中滿足 city_id < 100 的所有記錄,執行流程結束。

通過 optimizer trace 也可以驗證主查詢每讀取一條滿足 city_id < 100 的記錄,EXISTS 子查詢都要執行一次,如下:

{
"join_execution": {
"select#": 1,
"steps": [
{
// 主查詢一共有 99 滿足 where 條件的記錄
// steps 中有 99 個 subselect_execution
"subselect_execution": {
"select#": 2,
"steps": [
{
"join_execution": {
"select#": 2,
"steps": []
}
}
]
}
// 此處省略 98 個 subselect_execution
// ......
}
]
}
}

以下是 optimizer trace 的部分內容截圖,expanded_query 就是經過 MySQL 展開處理之后的 select 語句,我做了一些簡化和處理,如下:

圖片

join_execution 的 steps 后面,99 items 就是 99 個折疊起來的 subselect_execution。

5、最佳實踐

MySQL 讀取主查詢的一條記錄之后,判斷記錄是否匹配 where 條件,是按照我們寫 SQL 時字段在 where 條件中出現的順序進行判斷的。

由于判斷主查詢記錄是否匹配 IN 子查詢條件時,需要執行子查詢,成本比較高,所以,我們寫 SQL 的時候最好是把不包含子查詢的 where 條件放在前面,包含子查詢的 where 條件放在最后。

這個邏輯在《??MySQL 不相關子查詢怎么執行???》 中有過詳細介紹,這里不再重復了。

6、總結

本文主要介紹了以下內容:

  • 不相關子查詢轉換為相關子查詢之后,explain 結果中:
  • 子查詢 type 列的值 unique_subquery 是 eq_ref 的別名;index_subquery 是 ref 或 ref_or_null 的別名。
  • 子查詢 ref 列的值會顯示為 func,這是因為主查詢 IN 條件字段和子查詢 select 子句字段組成的新條件中,IN 條件字段引用了主查詢表中的字段,而不是直接使用主查詢表中的字段。
  • 不相關子查詢,如果不能轉換為半連接,則會在物化和相關子查詢兩種策略中二選一。
  • 兩種策略二選一的依據是子查詢執行成本,哪種執行成本低就選擇哪種。通過 optimizer trace 可以看到兩種執行策略的成本。
  • 簡單介紹了相關子查詢的執行流程。

本文轉載自微信公眾號「一樹一溪」,可以通過以下二維碼關注。轉載本文請聯系一樹一溪公眾號。

責任編輯:姜華 來源: 一樹一溪
相關推薦

2020-10-15 06:56:51

MySQL排序

2021-04-23 10:31:18

MySQLRole數據庫

2021-07-30 10:33:57

MySQL觸發器數據

2021-03-01 18:37:15

MySQL存儲數據

2023-09-22 17:36:37

2021-01-28 22:31:33

分組密碼算法

2020-05-22 08:16:07

PONGPONXG-PON

2018-06-07 13:17:12

契約測試單元測試API測試

2022-11-01 08:46:20

責任鏈模式對象

2021-01-29 08:32:21

數據結構數組

2023-05-15 08:38:58

模板方法模式

2023-07-06 13:56:14

微軟Skype

2022-08-08 08:25:21

Javajar 文件

2021-08-04 09:32:05

Typescript 技巧Partial

2018-11-29 09:13:47

CPU中斷控制器

2019-02-13 14:15:59

Linux版本Fedora

2021-02-06 08:34:49

函數memoize文檔

2020-08-12 08:34:16

開發安全We

2022-10-08 11:33:56

邊緣計算云計算

2020-06-28 09:30:37

Linux內存操作系統
點贊
收藏

51CTO技術棧公眾號

欧美少妇在线观看| 欧美日韩一区不卡| 久久久久久国产精品mv| 自拍自偷一区二区三区| 日韩中文字幕亚洲| 成年人黄色大片在线| 香蕉乱码成人久久天堂爱免费| 国产欧美日韩网站| 久久激情五月激情| 神马影院一区二区三区| 中文一区二区| www国产亚洲精品| 小处雏高清一区二区三区| 国产91ⅴ在线精品免费观看| 亚洲视频国产精品| 最近的2019中文字幕免费一页 | 欧美久久精品一级黑人c片 | 日韩电影二区| 欧美一级黑人aaaaaaa做受| 免费一级欧美在线观看视频| 亚洲天堂2020| 成人看片网站| 一区二区三区视频免费在线观看| 黑人巨大精品| 日本不卡电影| 国产精品免费小视频| 奇米影视亚洲| 成人做爰66片免费看网站| 亚洲午夜精品久久久久久app| 91亚洲午夜在线| 羞羞色午夜精品一区二区三区| 亚洲曰本av电影| 亚洲看片一区| 日本免费高清不卡| 国产一区福利在线| 无码aⅴ精品一区二区三区浪潮| 91浏览器在线视频| 一区二区三区免费播放| 亚洲图片欧美一区| jizz在线观看| 精品国产亚洲一区二区三区在线观看| 91九色美女在线视频| 国产午夜精品视频| aiss精品大尺度系列| 国产精品久久久一区| 一区二区三区四区五区精品视频| 亚洲一一在线| 久久青草国产手机看片福利盒子| 成人综合av| 欧美人妖巨大在线| 欧美成人精品一区二区男人小说| 久久精品国产91精品亚洲 | 原千岁中文字幕| 欧美喷潮久久久xxxxx| 精精国产xxxx视频在线野外| 久热精品视频在线观看| 999精品色在线播放| 偷拍视频一区二区| 国产欧美日韩在线| 美女做暖暖视频免费在线观看全部网址91 | 1区2区3区在线| 久久久久久久久亚洲| 我不卡神马影院| 一区二区不卡在线观看| 欧美国产乱子伦| 91社区在线观看播放| 综合欧美国产视频二区| 大片网站久久| 亚洲午夜激情网站| 午夜在线观看91| 亚洲午夜av电影| 欧美日韩国产传媒| 一级一片免费播放| 亚洲精品免费看| 丰满诱人av在线播放| 欧美黑人xxxx| 日韩高清一区在线| 美乳中文字幕| 亚洲系列中文字幕| 女生裸体视频一区二区三区| youjizz.com在线观看| 日韩欧美亚洲范冰冰与中字| 久久精品嫩草影院| 国产原创精品| 综合网在线视频| 91超碰免费在线| 91精品免费视频| 好男人看片在线观看免费观看国语| 日韩午夜三级在线| 久久青草视频| 午夜精品三级视频福利| 亚洲美女色禁图| 性欧美长视频免费观看不卡| 99精品在线观看| 50度灰在线观看| 欧美日韩在线播放三区| aaa国产精品视频| 亚洲精品白虎| 欧美日韩在线视频首页| 国产视频网站一区二区三区| 久久免费看av| 精品久久在线播放| 91麻豆精品激情在线观看最新| japanese在线视频| 91精品国产综合久久久蜜臀粉嫩| 国产欧美日韩影院| 国产亚洲天堂网| 亚洲欧美激情另类校园| 性色一区二区三区| 四虎影视在线播放| 日本中文字幕久久看| 久久久综合激的五月天| 悠悠资源网亚洲青| 国产一区二区三区无遮挡| 一区二区三区**美女毛片| 国产成年精品| 人人妻人人澡人人爽欧美一区双| 精品乱人伦小说| 在线亚洲精品| 日本福利午夜视频在线| 国产精品丝袜白浆摸在线| 国产午夜精品一区二区三区嫩草 | 国产在线中文字幕| 日韩av手机在线看| 国产精品伦理一区二区| 国产精品伦一区二区| 黄色网址在线免费看| 亚洲白虎美女被爆操| 亚洲麻豆av| 欧美黄色激情| 欧美一区二区福利| 欧美精选一区二区| 久久蜜桃精品| 超碰在线资源| 国产精品av免费观看| 亚洲一区二区久久久| 成人免费毛片a| 亚洲精品555| 亚洲爆乳无码专区| 91国产视频在线| 亚洲国产欧美一区二区三区丁香婷| 欧美日一区二区| 成人av电影观看| 亚洲ai欧洲av| 亚洲四色影视在线观看| 99久久精品国产一区二区三区| 美女日韩一区| jizz18欧美| 51国偷自产一区二区三区| 欧美高清一级片在线| 久久资源在线| 美女色狠狠久久| 天堂中文字幕一二区| 国产精品人成电影| 欧美亚洲国产一区在线观看网站| 在线亚洲激情| 忘忧草在线日韩www影院| 国产成人无码a区在线观看视频| 欧美裸体xxxx极品少妇| 一级精品视频在线观看宜春院 | 国产福利在线播放麻豆| 午夜久久久久久久久久久| 久久福利视频导航| 亚洲va韩国va欧美va精品| 亚洲深夜av| 性欧美hd调教| 美女av电影| 国产女主播一区二区三区| 日韩精品免费视频| 日本一区二区成人在线| 亚洲一级毛片| 都市激情亚洲一区| 福利片免费在线观看| 黄色99视频| 日韩中文字幕网址| 精品无人乱码一区二区三区| 免费看a级黄色片| 亚洲free性xxxx护士hd| 亚洲跨种族黑人xxx| 一卡二卡三卡日韩欧美| 男人的天堂亚洲| 影音先锋欧美激情| 成人动漫在线免费观看| 欧美国产激情视频| 成人影片在线播放| 日韩一级黄色av| 天天影视网天天综合色在线播放 | 国产嫩草一区二区三区在线观看| 一本色道久久88亚洲综合88| 亚洲成年人网站在线观看| 极品尤物av久久免费看| 日本不卡高清| 啪啪av大全导航福利综合导航| 午夜视频在线免费| 免费成人在线视频网站| 痴汉一区二区三区| 欧美激情影音先锋| 日韩av影视综合网| 欧美在线免费视屏| 亚洲精品免费看|