日本一区二区三区久久久久久久久不_日韩精品一区二区三区三区免费_精品视频一区二区不卡_欧美剧情片在线观看_欧美日韩免费在线视频_欧美成人精品3d动漫h_欧美激情中文字幕一区二区_91色九色蝌蚪_国产做a爰片久久毛片_久久久国产午夜精品_美女视频免费一区_日韩一级免费观看_日本一区二区三区四区在线视频_亚洲三级小视频_久久男人中文字幕资源站_欧美岛国在线观看

二維碼
企資網

掃一掃關注

當前位置: 首頁 » 企業資訊 » 行業 » 正文

庖丁解牛___圖解MySQL_8.0優化器查

放大字體  縮小字體 發布日期:2021-09-13 20:28:21    作者:企資小編    瀏覽次數:111
導讀

一 背景和架構我們都知道,利用編寫程序來動態實現我們應用所需要的邏輯,從而程序執行時得到我們需要的結果。那么數據庫就是一種通過輸入SQL字符串來快速獲取數據的應用。當然,假設沒有數據庫這種系統應用,用程序

一 背景和架構

我們都知道,利用編寫程序來動態實現我們應用所需要的邏輯,從而程序執行時得到我們需要的結果。那么數據庫就是一種通過輸入SQL字符串來快速獲取數據的應用。當然,假設沒有數據庫這種系統應用,用程序如何實現呢?我們可能會發現,即使不管數據如何存儲、數據是否并發訪問,仍然需要不斷通過修改程序處理不同應用對數據的不同請求。比如大數據領域,我們通常通過非關系型數據庫的API,實現對數據的獲取。然而這種方式雖然入門簡單,但是維護極難,而且通用性不強,即使不斷進行軟件架構設計或者抽象重構,仍然需要不斷地變換應用,這也是為何非關系型數據庫回頭擁抱數據庫SQL優化器的原因。

SQL優化器本質上是一種高度抽象化的數據接口的實現,經過該設計,客戶可以使用更通用且易于理解的SQL語言,對數據進行操作和處理,而不需要關注和抽象自己的數據接口,極大地解放了客戶的應用程序。

本文就來通過圖形解說的方式介紹下MySQL 8.0 SQL優化器如何把一個簡單的字符串(SQL),變成數據庫執行器可以理解的執行序列,最終將數據返還給客戶。強大的優化器是不需要客戶關注SQL如何寫的更好來更快獲得需要的數據,因此優化器對原始SQL一定會做一些等價的變化。在《MySQL 8.0 Server層最新架構詳解》一文中我們重點介紹了MySQL最新版本關于Server層解析器、優化器和執行器的總體介紹,包括一些代碼結構和變化的詳細展示,并且通過simple_joins函數拋磚引玉展示了MySQL優化器在邏輯變換中如何簡化嵌套Join的優化。本文我們會一步一步帶你進入神奇的優化器細節,詳細了解優化器優化部分的每個步驟如何改變著一個SQL最終的執行。

本文基于最新MySQL8.0.25版本,因為優化器轉換部分篇幅比較長,我們分成兩篇文章來介紹,第一部分介紹基于基本結構的Setup和Resolve的解析轉換過程,第二部分介紹更為復雜的子查詢、分區表和連接的復雜轉換過程,大綱如下:

Setup and Resolve

  • setup_tables : Set up table leaves in the query block based on list of tables.
  • resolve_placeholder_tables/merge_derived/setup_table_function/setup_materialized_derived : Resolve derived table, view or table function references in query block.
  • setup_natural_join_row_types : Compute and store the row types of the top-most NATURAL/USING joins.
  • setup_wild : Expand all '*' in list of expressions with the matching column references.
  • setup_base_ref_items : Set query_block's base_ref_items.
  • setup_fields : Check that all given fields exists and fill struct with current data.
  • setup_conds : Resolve WHERe condition and join conditions.
  • setup_group : Resolve and set up the GROUP BY list.
  • m_having_cond->fix_fields : Setup the HAVINg clause.
  • resolve_rollup : Resolve items in SELECt list and ORDER BY list for rollup processing.
  • resolve_rollup_item : Resolve an item (and its tree) for rollup processing by replacing items matching grouped expressions with Item_rollup_group_items and updating properties (m_nullable, PROP_ROLLUP_FIELD). Also check any GROUPING function for incorrect column.
  • setup_order : Set up the ORDER BY clause.
  • resolve_limits : Resolve OFFSET and LIMIT clauses.
  • Window::setup_windows1: Set up windows after setup_order() and before setup_order_final().
  • setup_order_final: Do final setup of ORDER BY clause, after the query block is fully resolved.
  • setup_ftfuncs : Setup full-text functions after resolving HAVINg.
  • resolve_rollup_wfs : Replace group by field references inside window functions with references in the presence of ROLLUP.

    二 詳細轉換過程

    轉換的整個框架是由Query_expression到Query_block調用prepare函數(sql/sql_resolver.cc)并且根據不同轉換規則的要求自頂向下或者自底向上的過程。

    圖片

    1 傳遞null到join的內表列表(propagate_nullability)

    prepare開始先要處理nullable table,它指的是table可能包含全為null的row,根據JOIN關系(top_join_list)null row可以被傳播。如果能確定一個table為nullable會使得一些優化退化,比如access method不能為EQ_REF、outer join不能優化為inner join等。

    2 解析設置查詢塊的leave_tables(setup_tables)

    SELECT  t1.c1FROM t1,     (SELECt       t2.c1     FROM t2,          (SELECt            t3.c1          FROM t3          UNIOn          SELECt            t4.c1          FROM t4) AS t3a) AS t2a;

    未在setup_table調用之前,每個Query_block的leaf_tables是為0的。

    該函數的作用就是構建leaf_tables,包括base tables和derived tables列表,用于后續的優化。setup_tables并不會遞歸調用,而是只解決本層的tables,并統計出本層derived table的個數。但是隨后會調用resolve_placeholder_tables()->resolve_derived()->derived(Query_expression)::prepare->Query_block::prepare來專門遞歸處理derived table對應的Query_expression。

    接下來我們根據prepare的調用順序,繼續看下針對于derived table處理的函數resolve_placeholder_tables。

    3 解析查詢塊Derived Table、View、Table函數 (resolve_placeholder_tables)

    這個函數用于對derived table、view和table function的處理,如果該table已經merged過了,或者是由于使用transform_grouped_to_derived()被調用到,已經決定使用materialized table方式,則直接忽略。

    前面已經介紹過resolve_derived()的作用,我們重點介紹merge_derived()函數,merge_derived是改變Query_expression/Query_block框架結構,將derived table或者view合并到到query block中。

    merge_derived 處理和合并Derived table

    1)merge_derived transformation的先決條件

  • 外層query block是否允許merge(allow_merge_derived)外層query block為nullptr外層query expression的子查詢為nullptr,derived table是第一層子查詢外層的外層query block可以allow_merge_derived=true,或者不包括外層的外層query block話是否為SELECt/SET
  • 外層lex是否可以支持merge(lex->can_use_merged()+lex->can_no_use_merged())
  • derived table是否已經被標記為需要物化materialize,比如創建視圖的方法是CREATE ALGORITHM=TEMPTABLE VIEW(derived_table->algorithm == VIEW_ALGORITHM_TEMPTABLE)
  • 整個dervived table所在的查詢表達式單元中,不能是(Query_expression::is_mergeable() ):Union查詢包含聚集、HAVINg、DISTINCT、WINDOWS或者LIMIT沒有任何table list
  • HINT或者optimizer_switch沒有禁止derived_merge
  • heuristic建議合并(derived_query_expressionmerge_heuristic())如果derived table包含的子查詢SELECT list依賴于自己的列時,不支持如果是dependant subquery需要多次執行時,不支持
  • derived table中如果查詢塊包含SEMI/ANTI-JOIN,并指定STRAIGHT_JOIN時,不支持
  • 如果合并的derived table和現有query block的leaf table count大約 MAX_TABLES時,不支持

    2)merge_derived transformation的轉換過程

  • 利用derived_table->nested_join結構來輔助處理OUTER JOIN的情況。
  • 把derived table中的表merge到NESTED_JOIN結構體(derived_table->merge_underlying_tables())
  • 將derived table中的所有表連接到父查詢的table_list列表中,同時把derived table從父查詢中刪除。
  • 對父查詢的所有相關數據結構進行重新計算(leaf_table_count,derived_table_count,table_func_count,materialized_derived_table_count,has_sj_nests,has_aj_nests,partitioned_table_count,cond_count,between_count,select_n_having_items)
  • 傳播設置父查詢OPTION_SCHEMA_TABLE(add_base_options())和如果是外查詢JOIN的內表,傳播設置nullable屬性(propagate_nullability())
  • 合并derived table的where條件到外查詢中(merge_where())
  • 建立對derived table需要獲取的列的引用(create_field_translation())
  • 將Derived table的結構從父查詢中刪除(exclude_level())
  • 將derived table中的列或者表的重命名合并到父查詢(fix_tables_after_pullout()/repoint_contexts_of_join_nests())
  • 因為已經把derived table中包含的表merge到了父查詢,所以需要對TABLE_LIST中的表所在的位置進行重新定位(remap_tables())
  • 將derived table合并到父查詢之后,需要重新修改原來derived table中所有對derived table中所有列的引用(fix_tables_after_pullout())
  • 如果derived table中包含ORDER By語句,如果滿足下列條件,derived table將會保留ORDER BY并合并到父查詢中,其他情況ORDER BY將會被忽略掉:如果父查詢允許排序并且正好是只有derived table不是一個UNIOn可以有WHERe條件,但是不能有group by或聚合函數本身并不是有序的

    過程簡化為:

    merge_derived 圖解過程

    看起來官方的derived merge還是不夠完美,無法自底向上的遞歸merge
    包含的opt trace:

    trace_derived.add_utf8_table(derived_table)       .add("select#", derived_query_block->select_number)       .add("merged", true);trace_derived.add_alnum("transformations_to_derived_table", "removed_ordering");

    該優化可以通過set optimizer_switch="derived_merge=on/off"來控制。

    setup_materialized_derived 設置物化Derived Table

    對于剩下不能采用 merge 算法的 derived table ,會轉為materialize 物化方式去處理。但此時只是做一些變量設置等預處理,實際的物化執行是在executor階段執行。

  • setup_materialized_derived_tmp_table(): 設置一個臨時表包含物化Derived Table的所有行數據。
  • check_materialized_derived_query_blocks(): 設置屬于當前Derived Table所在的查詢塊結構。
    trace_derived.add_utf8_table(this)       .add("select#", derived->first_query_block()->select_number)       .add("materialized", true);

    setup_table_function 處理表函數

    如果 query block 中有 table function,整個過程會處理兩遍。第一遍會跳過 table function 的 table ,第二遍才專門再對table function 的 table 執行一遍上述邏輯。這里的考慮應該是先 resolve 了外部環境(相對于table function),因為有可能函數參數會有依賴外部的 derived table。

    trace_derived.add_utf8_table(this)       .add_utf8("function_name", func_name, func_name_len)       .add("materialized", true);

    4 將SELECT *的通配符展開成具體的fields(setup_wild)

    5 建立Query_block級別的base_ref_items(setup_base_ref_items)

    base_ref_items記錄了所有Item的位置,方便查詢塊的其他Item可以進行引用,或者通過Item_ref及其Item_ref子類進行直接引用,例如子查詢的引用(Item_view_ref)、聚合函數引用(Item_aggregate_ref)、外查詢列的引用(Item_outer_ref)、subquery 子查詢產生NULL value的引用輔助(Item_ref_null_helper)。

    舉例說明比較復雜的Item_outer_ref:

    6 對select_fields進行fix_fields()和列權限檢查(setup_fields)

    下圖是比較復雜的帶子查詢的fixed field過程。有些field和表關聯,有的要添加相應的Item_xxx_ref引用。

    7 解析和fixed_fields WHERe條件和Join條件(setup_conds)

    setup_join_cond如果有nested_join會遞歸調用setup_join_cond進行解析和設置。這里也順帶介紹下simplify_const_condition函數的作用,如果發現可以刪除的const Item,則會用Item_func_true/Item_func_false來替代整個的條件,如圖。

    8 解析和設置ROLLUP語句(resolve_rollup)

    在數據庫查詢語句中,在 GROUP BY 表達式之后加上 WITH ROLLUP 語句,可以使得通過單個查詢語句來實現對數據進行不同層級上的分析與統計。

    SELECT YEAR,       country,       product,       SUM(profit) AS profitFROM salesGROUP BY YEAR,         country,         product WITH ROLLUP;+------+---------+------------+--------+| year | country | product    | profit |+------+---------+------------+--------+| 2000 | Finland | Computer   |   1500 || 2000 | Finland | Phone      |    100 || 2000 | Finland | NULL       |   1600 || 2000 | India   | Calculator |    150 || 2000 | India   | Computer   |   1200 || 2000 | India   | NULL       |   1350 || 2000 | USA     | Calculator |     75 || 2000 | USA     | Computer   |   1500 || 2000 | USA     | NULL       |   1575 || 2000 | NULL    | NULL       |   4525 || 2001 | Finland | Phone      |     10 || 2001 | Finland | NULL       |     10 || 2001 | USA     | Calculator |     50 || 2001 | USA     | Computer   |   2700 || 2001 | USA     | TV         |    250 || 2001 | USA     | NULL       |   3000 || 2001 | NULL    | NULL       |   3010 || NULL | NULL    | NULL       |   7535 |+------+---------+------------+--------+相當于做了下面的查詢:SELECt *FROM  (SELECt YEAR,          country,          product,          SUM(profit) AS profit   FROM sales   GROUP BY YEAR,            country,            product   UNIOn ALL SELECt YEAR,                    country,                    NULL,                    SUM(profit) AS profit   FROM sales   GROUP BY YEAR,            country   UNIOn ALL SELECt YEAR,                    NULL,                    NULL,                    SUM(profit) AS profit   FROM sales   GROUP BY YEAR   UNIOn ALL SELECt NULL,                    NULL,                    NULL,                    SUM(profit) AS profit   FROM sales) AS sum_tableORDER BY YEAR, country, product;+------+---------+------------+--------+| YEAR | country | product    | profit |+------+---------+------------+--------+| NULL | NULL    | NULL       |   7535 || 2000 | NULL    | NULL       |   4525 || 2000 | Finland | NULL       |   1600 || 2000 | Finland | Computer   |   1500 || 2000 | Finland | Phone      |    100 || 2000 | India   | NULL       |   1350 || 2000 | India   | Calculator |    150 || 2000 | India   | Computer   |   1200 || 2000 | USA     | NULL       |   1575 || 2000 | USA     | Calculator |     75 || 2000 | USA     | Computer   |   1500 || 2001 | NULL    | NULL       |   3010 || 2001 | Finland | NULL       |     10 || 2001 | Finland | Phone      |     10 || 2001 | USA     | NULL       |   3000 || 2001 | USA     | Calculator |     50 || 2001 | USA     | Computer   |   2700 || 2001 | USA     | TV         |    250 |+------+---------+------------+--------+

    排序由于有NULL的問題,所以分級匯總的效果非常難弄,而且group 列不同改變,SQL復雜度來回變化,而ROLLUP很簡單就可以實現效果,下面看下rollup在解析過程做了什么樣的轉換達到了意想不到的效果。

    9 解析和設置GROUP BY/ORDER BY語句(setup_group/setup_order)

    其中一個函數find_order_in_list(): 嘗試在select fields里去尋找可以映射的列,否則就得在最后投影的all fields里加上當前列,同時也做fix_fields。

  • m_having_cond->fix_fields : 對having條件進行fixed_fields。
  • resolve_limits : 處理OFFSET和LIMIT子句(offset_limit和select_limit的Items)。
  • setup_ftfuncs : 如果有full-text的函數,對相關Item進行fix_fields。

    remove_redundant_subquery_clause : 對于Table Subquery的表達式,通常是IN/ANY/ALL/EXISTS/etc,如果沒有聚合函數和Having子句,通??梢钥紤]刪除不必要的ORDER/DISTINCT/GROUP BY。該函數支持三種REMOVE_ORDER | REMOVE_DISTINCT | REMOVE_GROUP,如果是SINGLEROW_SUBS的子查詢,只考慮刪除REMOVE_ORDER。

    select c1 from t1 where t1.c2 in (select distinct c1 from t2 group by c1, c2 order by c1);轉化為 =>select c1 from t1 where t1.c2 in (select c1 from t2);
  • 處理是否可以刪除不必要的distinct語句,刪除的條件就是GROUP BY的列都在SELECt列表中,并且沒有ROLLUP和Window函數。
    is_grouped() && hidden_group_field_count == 0 && olap == UNSPECIFIED_OLAP_TYPE

    例如場景:

    SELECT DISTINCT c1, max(c2) from t1 group by c1;

    10 解析和設置Window函數(Window::setup_windows1)

    SELECt id,       release_year,       rating,       avg(rating) over(PARTITION BY release_year) AS year_avgFROM tw;+------+--------------+--------+-------------------+| id   | release_year | rating | year_avg          |+------+--------------+--------+-------------------+|    1 |         2015 |      8 |               8.5 ||    3 |         2015 |      9 |               8.5 ||    2 |         2015 |    8.5 |               8.5 ||    4 |         2016 |    8.2 |               8.3 ||    5 |         2016 |    8.4 |               8.3 ||    6 |         2017 |      7 |                 7 |+------+--------------+--------+-------------------+

    執行的過程和結果類似于下圖:

    我們看下它在開始Query_block::prepare解析過程做了哪些事情:

    select_lex->m_windows 不為空,就調用 Window::setup_windows1

  • 遍歷window函數列表,調用resolve_window_ordering來解析m_partition_by和m_order_by
  • 處理inter-window的引用關系(如WINDOW w1 AS (w2), w2 AS (), w3 AS (w1)),但必須是一個有向無環圖(DAG)
  • 重新遍歷檢查是否唯一名字check_unique_name、創建window partition by和window order by的引用items
  • 檢查窗口函數特征(Window::check_window_functions1(THD thd, _block select))首先判斷的是當前是靜態窗口還是動態窗口;靜態窗口即判斷了 frame 的定義是否有定義上下邊界。m_static_aggregates 為 true, 意味著是靜態窗口,同時對每一個分區都可以進行一次評估。如果 ma_static_aggregates 為 false, 則進一步判斷其滑動窗口使用的是基于范圍還是基于行。 m_row_optimizable 基于行 m_range_optimizable 基于范圍獲取聚合函數作為窗口函數時候窗口的特殊規格要求wfs->check_wf_semantics1(thd, select, &reqs) 這個方法其實就是判斷是不是需要row_buffer作為評估,如果我們只看當前分區的行無法進行正確的計算不需要,而需要看之后的或者之前的行,就需要使用row_buffer。

    三 綜述

    本文重點介紹了下優化器的基于規則的其中一部分優化,更多的偏重于SQL中的基本操作符,如表、列、函數、聚合、分組、排序等元素的解析和設置以及一些顯而易見的結構變化。下一篇文章我們將繼續介紹子查詢、分區表和JOIN操作的轉換部分,敬請期待。

    四 參考資料

  • 《MySQL 8.0 Server層最新架構詳解》
  • 《Mysql derived_MySQL · 新特性分析 · 5.7中Derived table變形記》
  • 《ROLLUP性能增強》
  • 《WL#9236, WL#9603 and WL#9727 - Add SQL window functions to MySQL》

    五 關于我們

    PolarDB 是阿里巴巴自主研發的云原生分布式關系型數據庫,于2020年進入Gartner全球數據庫Leader象限,并獲得了2020年中國電子學會頒發的科技進步一等獎。PolarDB 基于云原生分布式數據庫架構,提供大規模在線事務處理能力,兼具對復雜查詢的并行處理能力,在云原生分布式數據庫領域整體達到了國際領先水平,并且得到了廣泛的市場認可。在阿里巴巴集團內部的最佳實踐中,PolarDB還全面支撐了2020年天貓雙十一,并刷新了數據庫處理峰值記錄,高達1.4億TPS。歡迎有志之士加入我們,簡歷請投遞到daoke.wangc@alibaba-inc,期待與您共同打造世界一流的下一代云原生分布式關系型數據庫。


    作者 | 道客

    原文鏈接:click.aliyun/m/1000295120/

    本文為阿里云原創內容,未經允許不得轉載。

  •  
    (文/企資小編)
    免責聲明
    本文僅代表作發布者:企資小編個人觀點,本站未對其內容進行核實,請讀者僅做參考,如若文中涉及有違公德、觸犯法律的內容,一經發現,立即刪除,需自行承擔相應責任。涉及到版權或其他問題,請及時聯系我們刪除處理郵件:weilaitui@qq.com。
     

    Copyright ? 2016 - 2025 - 企資網 48903.COM All Rights Reserved 粵公網安備 44030702000589號

    粵ICP備16078936號

    微信

    關注
    微信

    微信二維碼

    WAP二維碼

    客服

    聯系
    客服

    聯系客服:

    在線QQ: 303377504

    客服電話: 020-82301567

    E_mail郵箱: weilaitui@qq.com

    微信公眾號: weishitui

    客服001 客服002 客服003

    工作時間:

    周一至周五: 09:00 - 18:00

    反饋

    用戶
    反饋

    日本一区二区三区久久久久久久久不_日韩精品一区二区三区三区免费_精品视频一区二区不卡_欧美剧情片在线观看_欧美日韩免费在线视频_欧美成人精品3d动漫h_欧美激情中文字幕一区二区_91色九色蝌蚪_国产做a爰片久久毛片_久久久国产午夜精品_美女视频免费一区_日韩一级免费观看_日本一区二区三区四区在线视频_亚洲三级小视频_久久男人中文字幕资源站_欧美岛国在线观看
    国产欧美日韩综合一区在线观看| 美女网站一区二区| 日韩欧美电影一二三| 91精品国产入口| 日韩一级黄色大片| 久久久欧美精品sm网站| 欧美高清在线视频| 一区二区三区中文字幕电影| 午夜久久福利影院| 国产精品99精品久久免费| 不卡一区二区三区四区| av成人观看| 亚洲mv在线看| 欧美日本免费一区二区三区| 久久亚洲精精品中文字幕早川悠里 | 国产精品99久久久久久久vr| 成人app在线观看| 韩国一区二区三区美女美女秀| 日本午夜精品电影| 欧美日韩国产小视频在线观看| 久久综合九色欧美综合狠狠 | 欧美丝袜丝交足nylons| 日韩欧美成人一区二区| 一区视频在线播放| 老司机午夜精品| 99久久久久国产精品免费| 欧美日韩一区二区三区在线视频 | 亚洲va国产天堂va久久en| 久久99国内精品| 国产传媒欧美日韩| 色素色在线综合| 久久精品一区二区三区不卡牛牛| 一区二区三区欧美日韩| 国产综合色产在线精品| 国产乱码精品一区二区三区中文| 一本一本大道香蕉久在线精品| 日韩视频免费观看高清完整版在线观看 | 国产精品二区三区四区| 色94色欧美sute亚洲13| 久久人人超碰精品| 日本麻豆一区二区三区视频| 99视频精品全部免费在线| 日韩国产一区久久| 亚洲精品一区二区三区在线观看 | 久久精品国产久精国产| av成人午夜| 欧美午夜一区二区| 亚洲少妇最新在线视频| 国产九色精品成人porny| 丝袜美腿玉足3d专区一区| 精品国产污网站| 免费人成在线不卡| 免费一区二区三区| 欧美精品一区在线观看| 日本欧美一区二区三区乱码| 国产91一区二区三区| 69堂成人精品免费视频| 夜夜精品浪潮av一区二区三区| 成人精品gif动图一区| 在线观看日韩电影| 亚洲午夜精品一区二区三区他趣| 51国偷自产一区二区三区的来源| 欧美日韩中文精品| 天堂资源在线中文精品| 久久婷婷开心| 欧美激情一区二区| 懂色av一区二区在线播放| 一本到不卡免费一区二区| 亚洲图片激情小说| 91视频免费播放| 日韩三级高清在线| 国产在线看一区| 欧美亚洲综合在线| 日韩激情视频网站| 亚洲激情一区二区| 一区二区三区在线视频免费| 国产精品福利视频| 国产欧美一区视频| 99精品热视频| 精品毛片乱码1区2区3区| 国产一区二区三区精品欧美日韩一区二区三区 | 99久久精品无码一区二区毛片| 制服.丝袜.亚洲.另类.中文| 免费观看91视频大全| 亚洲国产精品一区二区第一页| 亚洲婷婷综合色高清在线| 国产乱码精品一区二区三区卡| 国产日韩高清在线| 99re66热这里只有精品3直播 | 日本一道高清亚洲日美韩| 日本亚洲导航| 亚洲国产精品人人做人人爽| 色之综合天天综合色天天棕色| 亚洲黄色尤物视频| 日韩视频精品| 亚洲一级二级三级| 亚洲春色在线| 日韩国产精品大片| 在线亚洲免费视频| 久久99国产精品成人| 欧美色偷偷大香| 经典三级视频一区| 欧美一区二区在线观看| 丁香六月久久综合狠狠色| 精品国产露脸精彩对白| 91在线视频免费观看| 中文字幕av一区二区三区| 九色视频成人porny| 一区二区三区四区蜜桃| 伊人av成人| 激情综合网av| 日韩限制级电影在线观看| 91网上在线视频| 成人免费视频在线观看| 日韩欧美手机在线| 青青草97国产精品免费观看 | 国产手机精品在线| 一区二区三区中文在线| 色吧成人激情小说| 国产高清精品在线| 国产亚洲短视频| 欧美精品成人一区二区在线观看| 亚洲五码中文字幕| 欧美三级日韩三级| 99久久婷婷国产| 中文字幕一区二区三区在线观看| 欧美精品欧美精品| 久久精品久久综合| 精品国产露脸精彩对白 | 这里只有精品视频在线观看| av在线播放成人| 中文字幕日韩精品一区| 一区二区三区四区视频在线| 国产乱码精品一区二区三区五月婷| 精品久久久久久久久久久院品网| 国产精品制服诱惑| 日韩主播视频在线| 日韩精品自拍偷拍| 日本电影一区二区三区| 日产国产欧美视频一区精品| 制服丝袜av成人在线看| 国产一区二区三区奇米久涩| 午夜欧美大尺度福利影院在线看| 56国语精品自产拍在线观看| 国产传媒欧美日韩| 九色|91porny| 综合色天天鬼久久鬼色| 欧美日韩三级一区| 国产伦精品一区二区三区四区视频| 视频精品一区二区| 久久免费视频一区| 色婷婷久久久久swag精品| 999在线观看免费大全电视剧| 日精品一区二区| 国产精品美女久久久久av爽李琼| 在线视频一区二区三| 国产精品区一区| 国产精品白丝jk白祙喷水网站| 樱花影视一区二区| 国产日本一区二区三区| 国产综合色精品一区二区三区| 成人免费一区二区三区在线观看| 欧美日本乱大交xxxxx| 精品国产一区二区三区免费 | 欧美中文一区二区三区| 91在线免费看片| 麻豆精品一区二区| 亚洲精品成人悠悠色影视| 精品伦理精品一区| 色噜噜狠狠一区二区三区果冻| 91麻豆蜜桃| 国产一区二区免费在线| 午夜一区二区三区在线观看| 国产精品三级在线观看| 日韩欧美综合在线| 欧美系列日韩一区| 亚洲欧美影院| 国产一区二区三区黄| 9人人澡人人爽人人精品| 蜜臀99久久精品久久久久久软件| 亚洲人被黑人高潮完整版| 精品国产乱码91久久久久久网站| 欧美日韩一区二区不卡| 这里只有精品66| 久久久久久久久一区| 91手机在线播放| 国产69精品久久99不卡| 青青草成人在线观看| 一区二区三区av电影| 中文字幕精品综合| 日韩精品影音先锋| 555www色欧美视频| 色综合一区二区| 免费国产一区二区| 国产精品一区二区三区不卡| 成人高清伦理免费影院在线观看| 激情都市一区二区| 久久成人免费网站| 肉色丝袜一区二区| 婷婷丁香久久五月婷婷|