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

探究Presto SQL引擎(2)-淺析Join

大數據
本文梳理了Join的原理,以及Join算法在Presto中的實現思路。通過理論和實踐的結合,可以在理解原理的基礎上,更加深入理解Join算法在OLAP場景下的工程落地技巧,比如火山模型,列式存儲,批量處理等思想的應用。

在《探究Presto SQL引擎(1)-巧用Antlr》中,我們介紹了Antlr的基本用法以及如何使用Antlr4實現解析SQL查詢CSV數據,更加深入理解Presto查詢引擎支持的SQL語法以及實現思路。

本次帶來的是系列文章的第2篇,本文梳理了Join的原理,以及Join算法在Presto中的實現思路。通過理論和實踐的結合,可以在理解原理的基礎上,更加深入理解Join算法在OLAP場景下的工程落地技巧,比如火山模型,列式存儲,批量處理等思想的應用。

一、背景

在業務開發中使用數據庫,通常會有規范不允許過多表的Join。例如阿里巴巴開發手冊中,有如下的規定:

【強制】超過三個表禁止Join。需要Join的字段,數據類型必須絕對一致;多表關聯查詢時,保證被關聯的字段需要有索引。說明:即使雙表Join也要注意表索引、SQL性能。

在大數據數倉的建設中,盡管我們有星型結構和雪花結構,但是最終交付業務使用的大多是寬表。

可以看出業務使用數據庫中的一個矛盾點:我們需要Join來提供靈活的關聯操作,但是又要盡量避免多表和大表Join帶來的性能問題。這是為什么呢?

二、Join的基本原理

在數據庫中Join提供的語義是非常豐富的。簡單總結如下:

通常理解Join的實現原理,從Cross Join是最好的切入點,也就是所謂的笛卡爾積。對于集合進行笛卡爾積運算,理解非常簡單,就是窮舉兩個集合中元素所有的組合情況。在數據庫中,集合就對應到數據表中的所有行(tuples),集合中的元素就對應到單行(tuple)。所以實現Cross Join的算法也就呼之欲出了。實現的代碼樣例如下:

List  r = newArrayList(
new Tuple(newArrayList(1,"a")),
new Tuple(newArrayList(2,"b")));
List s = newArrayList(
new Tuple(newArrayList(3,"c")),
new Tuple(newArrayList(4,"d")));
int cnt =0;
for(Tuple ri:r){
for(Tuple si:s){
Tuple c = new Tuple().merge(ri).merge(si);
System.out.println(++cnt+": "+ c);
}
}
/**
? out:
1: [1, a, 3, c]
2: [1, a, 4, d]
3: [2, b, 3, c]
4: [2, b, 4, d]
*/

可以看出實現邏輯非常簡單,就是兩個For循環嵌套。

2.1 Nested Loop Join算法

在這個基礎上,實現Inner Join的第一個算法就順其自然了。非常直白的名稱:Nested Loop,,實現關鍵點如下:

(來源:Join Processing in Relational Databases)

其中,θ操作符可以是:=, !=, <, >, ≤, ≥。

相比笛卡爾積的實現思路,也就是添加了一層if條件的判斷用于過濾滿足條件的組合。

對于Nested Loop算法,最關鍵的點在于它的執行效率。假如參與Join的兩張表一張量級為1萬,一張量級為10w,那么進行比較的次數為1w*10w=10億次。在大數據時代,通常一張表數據量都是以億為單位,如果使用Nested Loop Join算法,那么Join操作的比較次數直接就是天文數字了。所以Nested Loop Join基本上是作為萬不得已的保底方案。Nested Loop這個框架下,常見的優化措施如下:

  • 小表驅動大表,即數據量較大的集作為于for循環的內部循環。
  • 一次處理一個數據塊,而不是一條記錄。也就是所謂的Block Nested Loop Join,通過分塊降低IO次數,提升緩存命中率。

值得一提的是Nested Loop Join的思想雖然非常樸素,但是天然的具備分布式、并行的能力。這也是為什么各類NoSQL數據庫中依然保留Nested Loop Join實現的重要一點。雖然單機串行執行慢,但是可以并行化的話,那就是加機器能解決的問題了。

2.2 Sort Merge Join算法

通過前面的分析可以知道,Nested Loop Join算法的關鍵問題在于比較次數過多,算法的復雜度為O(m*n),那么突破口也得朝著這個點。如果集合中的元素是有序的,比較的次數會大幅度降低,避免很多無意義的比較運算。對于有序的所以Join的第二種實現方式如下所描述:

(來源:Join Processing in Relational Databases)

通過將JOIN操作拆分成Sort和Merge兩個階段實現Join操作的加速。對于Sort階段,是可以提前準備好可以復用的。這樣的思想對于MySQL這類關系型數據庫是非常友好的,這也能解釋阿里巴巴開發手冊中要求關聯的字段必須建立索引,因為索引保證了數據有序。該算法時間復雜度為排序開銷O(mlog(m)+nlog(n))+合并開銷O(m+n)。但是通常由于索引保證了數據有序,索引其時間復雜度為O(m+n)。

2.3 Hash Join算法

Sort Merge Join的思想在落地中有一定的限制。所謂成也蕭何敗蕭何,對于基于Hadoop的數倉而言,保證數據存儲的有序性這個點對于性能影響過大。在海量數據的背景下,維護索引成本是比較大的。而且索引還依賴于使用場景,不可能每個字段都建一個索引。在數據表關聯的場景是大表關聯小表時,比如:用戶表(大表)--當日訂單表(小表);事實表(大表)–維度表(小表),可以通過空間換時間。回想一下,在基礎的數據結構中,tree結構和Hash結構可謂數據處理的兩大法寶:一個保證數據有序方便實現區間搜索,一個通過hash函數實現精準命中點對點查詢效率高。

在這樣的背景下,通過將小表Hash化,實現Join的想法也就不足為奇了。

(來源:Join Processing in Relational Databases)

而且即使一張表在單機環境生成Hash內存消耗過大,還可以利用Hash將數據進行切分,實現分布式能力。所以,在Presto中Join算法通常會選擇Hash Join,該算法的時間復雜度為O(m+n)。

通過相關資料的學習,可以發現Join算法的實現原理還是相當簡單的,排序和Hash是數據結構最為基礎的內容。了解了Join的基本思想,如何落地實踐出來呢?畢竟talk is cheap。在項目中實現Join之前,需要一些鋪墊知識。通常來說核心算法是皇冠上的明珠,但是僅有明珠是不夠的還需要皇冠作為底座。

三、Join工程化前置條件

3.1 SQL處理架構-火山模型

在將Join算法落地前,需要先了解一下數據庫處理數據的基本架構。在理解架構的基礎上,才能將Join算法放置到合適的位置。在前面系列文章中探討了基于antlr實現SQL語句的解析。可以發現SQL語法支持的操作類型非常豐富:查詢表(TableScan),過濾數據(Filter),排序(Order),限制(Limit),字段進行運算(Project), 聚合(Group),關聯(Join)等。為了實現上述的能力,需要一個具備并行化能力且可擴展的架構。

1994年Goetz Graefe在論文《Volcano-An Extensible and Parallel Query Evaluation System》提出了一個架構設計思想,這就是大名鼎鼎的火山模型,也稱為迭代模型。火山模型其實包含了文件系統和查詢處理兩個部分,這里我們重點關注查詢處理的設計思想。架構圖如下:

(來源:《Balancing vectorized execution with bandwidth-optimized storage》)

簡單解讀一下:

職責分離:將不同操作獨立成一個的Operator,Operator采用open-next-close的迭代器模式。例如對于SQL 。

SELECT Id, Name, Age, (Age - 30) * 50 AS Bonus
FROM People
WHERE Age > 30

對應到Scan, Select, Project三個Operator,數據交互通過next()函數實現。上述的理論在Presto中可以對應起來,例如Presto中幾個常用的Operator, 基本上是見名知意:

動態組裝:Operator基于SQL語句的解析實現動態組裝,多個Operator形成一個管道(pipeline)。例如:print和predicate兩個operator形成一個管道:

(來源: 《Volcano-An Extensible and Parallel Query Evaluation System》)

在火山模型的基礎上,Presto吸收了數據庫領域的其他思想,對基礎的火山模型進行了優化改造,主要體現在如下幾點:

  • Operator數據處理優化成一次一個Page,而不是一次行(也稱為tuple)。
  • Page的存儲采用列式結構。即相同的列封裝到一個Block中。

批量處理結合列式存儲奠定了向量化計算的基礎。這也是數據庫領域的優化方向。

3.2 批量處理和列式存儲

在研讀Presto源碼時,幾乎到處都可以看到Page/Block的身影。所以理解Page/Block背后的思想是理解Presto實現機制的基礎。有相關書籍和文檔講解Page/Block的概念,但是由于這些概念是跟其他概念混在一起呈現,導致一時間不容易理解。

筆者認為Type-Block-Page三者放在一起,更容易理解。我們使用數據庫,通常需要定義表,字段名稱,字段類型。在傳統的DBMS中,通常是按行存儲數據,通常結構如下:

(來源:《數據庫系統實現》)

但是通常OLAP場景不需要讀取所有的字段,基于這樣的場景,就衍生出來了列式存儲。就是我們看到的如下結構:

(來源:《Presto技術內幕》)

即每個字段對應一個Block, 多個Block的切面才是一條記錄,也就是所謂的行,在一些論文中稱為tuple。通過對比可以清楚看出Presto中,Page就是典型了列式存儲的實現。所以在Presto中,每個Type必然會關聯到一種Block。例如:bigint類型就對應著LongArrayBlockBuilder,varchar類型對應著VariableWidthBlock。

理解了原理,操作Page/Block就變得非常簡單了,簡單的demo代碼如下:

import com.facebook.presto.common.Page;
import com.facebook.presto.common.PageBuilder;
import com.facebook.presto.common.block.Block;
import com.facebook.presto.common.block.BlockBuilder;
import com.facebook.presto.common.type.BigintType;
import com.facebook.presto.common.type.Type;
import com.facebook.presto.common.type.VarcharType;
import com.google.common.collect.Lists;
import io.airlift.slice.Slice;
import java.util.List;
import static io.airlift.slice.Slices.utf8Slice;
/**
? PageBlockDemo
?
? @version 1.0
? @since 2021/6/22 19:26
*/
public class PageBlockDemo {
private static Page buildPage(List types,List<Object[]> dataSet){
PageBuilder pageBuilder = new PageBuilder(types);
// 封裝成Page
for(Object[] row:dataSet){
// 完成一行
pageBuilder.declarePosition();
for (int column = 0; column < types.size(); column++) {
BlockBuilder out = pageBuilder.getBlockBuilder(column);
Object colVal = row[column];
if(colVal == null){
out.appendNull();
}else{
Type type = types.get(column);
Class<?> javaType = type.getJavaType();
if(javaType == long.class){
type.writeLong(out,(long)colVal);
}else if(javaType == Slice.class){
type.writeSlice(out, utf8Slice((String)colVal));
}else{
throw new UnsupportedOperationException("not implemented");
}
}
}
}
// 生成Page
Page page = pageBuilder.build();
pageBuilder.reset();
return page;
}
private static void readColumn(List types,Page page){
// 從Page中讀取列
for(int column=0;column<types.size();column++){
Block block = page.getBlock(column);
Type type = types.get(column);
Class<?> javaType = type.getJavaType();
System.out.print("column["+type.getDisplayName()+"]>>");
List<Object> colList = Lists.newArrayList();
for(int pos=0;pos<block.getPositionCount();pos++){
if(javaType == long.class){
colList.add(block.getLong(pos));
}else if(javaType == Slice.class){
colList.add(block.getSlice(pos,0,block.getSliceLength(pos)).toStringUtf8());
}else{
throw new UnsupportedOperationException("not implemented");
}
}
System.out.println(colList);
}
}
public static void main(String[] args) {
/**
* 假設有兩個字段,一個字段類型為int, 一個字段類型為varchar
*/
List types = Lists.newArrayList(BigintType.BIGINT, VarcharType.VARCHAR);
}
public static void main(String[] args) {
/**
* 假設有兩個字段,一個字段類型為int, 一個字段類型為varchar
*/
List types = Lists.newArrayList(BigintType.BIGINT, VarcharType.VARCHAR);
// 按行存儲
List<Object[]> dataSet = Lists.newArrayList(
new Object[]{1L,"aa"},
new Object[]{2L,"ba"},
new Object[]{3L,"cc"},
new Object[]{4L,"dd"});

Page page = buildPage(types, dataSet);
readColumn(types,page);
}
}
// 運行結果:
//column[bigint]>>[1, 2, 3, 4]
//column[varchar]>>[aa, ba, cc, dd]

將數據封裝成Page在各個Operator中流轉,一方面避免了對象的序列化和反序列化成本,另一方面相比tuple的方式降低了函數調用的開銷。這跟集裝箱運貨降低運輸成本的思想是類似的。

四、Join算法的工程實踐

理解了Join的核心算法和基礎架構,結合前文中對antlr實現SQL表達式的解析以及實現where條件過濾,我們已經具備了實現Join的基礎條件。接下來簡單講述一下Join算法的落地流程。首先在語法層面需要支持Join的語法,由于本文目的在于研究算法實現流程,而不在于實現完整的Join功能,因此我們暫且先考慮支持兩張表單字段的等值Join語法。

首先在語法上需要支持Join, 基于antlr語法的定義關鍵點如下:

querySpecification
: SELECT selectItem (',' selectItem)*
(FROM relation (',' relation)*)?
(WHERE where=booleanExpression)?
;
selectItem
: expression #selectSingle
;
relation
: left=relation
(
joinType JOIN rightRelation=relation joinCriteria
) #joinRelation
| sampledRelation #relationDefault
;
joinType
: INNER?
;
joinCriteria
: ON booleanExpression
;

上述的語法定義將Join的關鍵要素拆解得非常清晰:Join的左表, Join的類型,Join關鍵詞, Join的右表, Join的關聯條件。例如,通常我們最簡單的Join語句用例如下(借用presto的tpch數據源):

select t2.custkey, t2.phone, t1.orderkey from orders t1 inner join customer t2 on t1.custkey=t2.custkey limit 10;

對應著語法和SQL語句用例,可以看到在將Join算法落地,還需要考慮如下細節點:

  • 檢測SQL語句,確保SQL語句符合語法要求。
  • 梳理表的別名和字段的對應關系,確保查詢的字段和表能夠對應起來,Join條件的字段類型能夠匹配。
  • Join算法的選取,是HashJoin還是NestedLoopJoin還是SortMergeJoin?  
  • 哪個表是build表,哪個表是probe表?
  • Join條件的判斷如何實現?
  • 整個查詢涉及到Operator如何組裝,以實現最終結果的輸出?

我們回顧一下SQL執行的關鍵流程:

(來源: Query Execution Flow Architecture (SQL Server))

基于上面的流程,問題其實已經有了答案。

  • Parser:  借助antlr的能力即可實現SQL語法的檢測。
  • Binding: 基于SQL語句生成AST,利用元數據檢測字段和表的映射關系以及Join條件的字段類型。
  • Planner: 基于AST生成查詢計劃。  
  • Executor: 基于查詢計劃生成對應的Operator并執行。

以NestedLoop Join算法為例,了解一下Presto的實現思路。對于NestedLoopJoin Join算法的落地,在Presto中其實是拆解為兩個階段:組合階段和過濾階段。在實現JoinOperator時,只需負責兩個表數據的笛卡爾積組合即可。核心代碼如下:

// NestedLoopPageBuilder中實現兩個Page計算笛卡爾積的處理邏輯,這里RunLengthEncodedBlock用于一個元素復制,典型地笛卡爾積計算中需要將一列元素從1行復制成多行。
@Override
public Page next()
{
if (!hasNext()) {
throw new NoSuchElementException();
}
if (noColumnShortcutResult >= 0) {
rowIndex = maxRowIndex;
return new Page(noColumnShortcutResult);
}
rowIndex++;

// Create an array of blocks for all columns in both pages.
Block[] blocks = new Block[numberOfProbeColumns + numberOfBuildColumns];
// Make sure we always put the probe data on the left and build data on the right.
int indexForRleBlocks = buildPageLarger ? 0 : numberOfProbeColumns;
int indexForPageBlocks = buildPageLarger ? numberOfProbeColumns : 0;
// For the page with less rows, create RLE blocks and add them to the blocks array
for (int i = 0; i < smallPage.getChannelCount(); i++) {
Block block = smallPage.getBlock(i).getSingleValueBlock(rowIndex);
blocks[indexForRleBlocks] = new RunLengthEncodedBlock(block, largePage.getPositionCount());
indexForRleBlocks++;
}
// Put the page with more rows in the blocks array
for (int i = 0; i < largePage.getChannelCount(); i++) {
blocks[indexForPageBlocks + i] = largePage.getBlock(i);
}
return new Page(largePage.getPositionCount(), blocks);
}

五、小結

本文簡單梳理了Join的基本算法以及在Presto中實現的基本框架,并以NestedLoop Join算法為例,演示了在Presto中的實現核心點。可以看出相比原始的算法描述,Presto的工程落地是截然不同: 不僅支持了所有的Join語義,而且實現了分布式能力。這其中有架構層面的思考,也有性能層面的思考,非常值得探索跟研究。就Join算法,可以探索的點還有很多,比如多表Join的順序選取,大表跟小表Join的算法優化,Semi Join的算法優化,Join算法數據傾斜的問題等等,可謂路漫漫其修遠兮,將在后續系列文章中繼續分析探索。

責任編輯:龐桂玉 來源: vivo互聯網技術
相關推薦

2022-10-27 10:06:16

Presto SQLAntlr大數據

2022-10-27 11:31:10

Presto SQL統計計數大數據

2022-10-27 11:07:40

2021-11-30 07:49:00

大數據工具 Presto

2010-09-30 11:16:53

J2ME Snake腳

2010-04-09 12:20:11

Oracle SQL

2016-12-08 10:57:08

渲染引擎前端優化

2025-08-07 01:00:00

2009-09-16 17:11:35

LINQ To SQL

2009-09-10 18:02:23

LINQ to SQL

2009-09-16 17:15:57

正則表達式引擎

2011-11-01 09:42:44

WP7交互設計

2022-09-27 21:22:02

SQL Server數據庫

2011-03-07 13:27:13

SQLCase

2022-09-29 19:37:09

SQL Server數據庫

2017-01-19 19:46:21

Opera Prest代碼瀏覽器

2020-03-20 10:14:49

搜索引擎倒排索引

2009-09-17 17:34:23

linq to sql

2009-09-14 09:46:00

LINQ to SQL

2009-09-17 18:05:15

linq to sql
點贊
收藏

51CTO技術棧公眾號

精品国产3级a| 国产人久久人人人人爽| 视频一区视频二区国产精品 | 九九热视频在线观看| 午夜影视一区二区三区| 久久一区二区视频| 国产在线观看一区二区三区 | 亚洲成人免费看| 欧美日韩成人一区二区三区| 激情五月激情综合| 视频在线观看免费影院欧美meiju 视频一区中文字幕精品 | 国产日韩av高清| 精品少妇theporn| 最新亚洲精品| 日韩午夜在线观看| 欧美黄色一级片视频| 麻豆网在线观看| 99久久夜色精品国产网站| 国产精品视频内| 日韩精品成人在线| 欧美韩国日本在线观看| 亚洲福利小视频| 91亚洲精品久久久蜜桃借种| 国产白浆在线免费观看| 自拍av一区二区三区| 国产91精品高潮白浆喷水| 国产精品久久久久久久av| 91久久偷偷做嫩草影院电| 亚洲色图丝袜美腿| 久久久久天天天天| av大片免费在线观看| 日韩欧美中文| 亚洲精品日韩欧美| www.黄色网| 亚洲国产一区二区久久| 日韩欧美精品网站| 97在线国产视频| 国产精品剧情| 国产精品毛片无遮挡高清| 美女被啪啪一区二区| www夜片内射视频日韩精品成人| 天堂蜜桃91精品| 久久免费精品视频| 亚洲调教欧美在线| 日韩精品免费视频一区二区三区 | 久久这里只有精品99| 国产伦精品一区二区三区妓女| 日本综合精品一区| 91精品国产一区二区人妖| 亚洲午夜久久久影院伊人| 无码精品视频一区二区三区| 国产高清在线精品| 欧美激情一二区| 手机av在线看| 日韩片欧美片| 中文在线资源观看视频网站免费不卡| 9.1成人看片免费版| 老司机凹凸av亚洲导航| 精品免费日韩av| aaaaaaaa毛片| 九九99久久精品在免费线bt| 欧美美女一区二区| 久久婷婷中文字幕| 国产日本亚洲| 亚洲mv在线观看| 欧美乱做爰xxxⅹ久久久| 99热国产在线| 亚洲一区中文日韩| 婷婷五月综合缴情在线视频| 大黄网站在线观看| 午夜精品影院在线观看| 久在线观看视频| 美女18一级毛片一品久道久久综合| 五月婷婷激情综合| 男人操女人逼免费视频| 超碰一区二区| 欧美性色欧美a在线播放| 国产一二三区av| 污污网站在线看| 亚洲中国最大av网站| 成人免费在线网| 极品av在线| 在线精品视频免费播放| 依人在线免费视频| 欧美aaaaa性bbbbb小妇| 岛国av在线不卡| 国产综合免费视频| 久久夜夜久久| 日韩视频中午一区| 久久人人爽人人爽人人片| 国产精品手机在线播放| 久久精品免费电影| 亚洲一区二区三区综合| 久久不见久久见中文字幕免费| 亚洲人成网在线播放| 亚洲色图27p| 国产综合视频| 国产成人鲁鲁免费视频a| 一本久道久久综合无码中文| 免费在线欧美黄色| 国产精品中文字幕久久久| 国产熟女一区二区丰满| 91在线播放网址| 亚洲成色最大综合在线| 欧美人与动牲性行为| 欧美国产日本视频| 国产人妻互换一区二区| 岛国av在线网站| 欧美日韩视频专区在线播放| 天天躁日日躁狠狠躁av| 日本久久黄色| 91精品国产亚洲| 国产又粗又猛又黄又爽| 97久久超碰国产精品| 国产成年人在线观看| 电影在线一区| 亚洲国产视频直播| 日韩av在线中文| 欧美黄色录像| 久久人人爽亚洲精品天堂| 五月天激情国产综合婷婷婷| 亚洲人www| 国产精品自拍偷拍| 女人18毛片水真多18精品| 国产精品少妇自拍| 日韩免费视频播放| 日韩综合一区二区三区| 最近免费中文字幕视频2019| 亚洲精品视频在线观看免费视频| 看国产成人h片视频| 精品午夜一区二区三区| 少女频道在线观看免费播放电视剧| 日本丶国产丶欧美色综合| 一级少妇精品久久久久久久| 国产精品久久观看| 国产精品日韩专区| 四虎在线观看| 久久你懂得1024| 国产美女作爱全过程免费视频| 黄色精品视频网站| 中文字幕久热精品视频在线| 国内精品福利视频| a美女胸又www黄视频久久| 国产激情片在线观看| 四虎影视成人精品国库在线观看 | 色综合888| 亚洲午夜久久久久久久久电影院| 中文字幕一区二区在线观看视频 | 97久久精品人人爽人人爽蜜臀| av久久久久久| 中文字幕一区二区三区日韩精品| 久久中文字幕在线| 999免费视频| 亚洲美腿欧美偷拍| 成人高清在线观看视频| 91成人国产| 亚洲xxx自由成熟| av免费在线观看网址| 欧美一卡在线观看| 精品欧美一区二区久久久久| 国产精品一区免费在线观看| 精品一区二区三区毛片| 成人av在线播放| 欧美裸体xxxx极品少妇| 亚洲国产精品久久久久久久 | 国产一区二区三区三区在线观看| 日本视频在线观看免费| 日本视频免费一区| 91久久精品日日躁夜夜躁国产| 午夜在线观看视频| 欧美区在线观看| 精品无码一区二区三区蜜臀| 国产美女娇喘av呻吟久久| 男人天堂成人网| 视频精品一区| 午夜精品在线视频| 国产香蕉视频在线看| 欧美日韩一区不卡| 99久久婷婷国产综合| 国产成人亚洲精品狼色在线| 岛国大片在线播放| 精品大片一区二区| 国产综合在线观看视频| 亚洲妇熟xxxx妇色黄| 亚洲国产精品热久久| 日韩 欧美 中文| 中文字幕免费不卡在线| 欧美日韩一区二区区| 亚洲人妖在线| 日韩伦理一区二区三区av在线| 亚洲欧美在线人成swag| 久久久久久久激情视频| 蜜芽tv福利在线视频| 欧美猛男男办公室激情| 久久久精品视频免费| 国产欧美一区二区精品性色| 欧美一级视频在线| 亚洲视频成人| 伊人婷婷久久| 老汉色老汉首页av亚洲| 国产日韩欧美在线播放| 成人免费图片免费观看| 日韩中文字在线| 天堂中文在线资源| 欧美日韩aaaaa| 久久久久久久极品| 日韩美女视频一区二区| 黄瓜视频污在线观看| 激情综合色播激情啊| 五月天国产一区| 国产亚洲观看| 国产精品99导航| 久久免费电影| 日韩视频在线免费观看| 午夜小视频在线播放| 在线成人免费视频| 日本高清不卡码| 一区二区三区日韩| 亚洲丝袜在线观看| 日韩在线观看一区二区| 亚洲人成无码网站久久99热国产| 欧美电影免费播放| 欧美二区在线| 国产精品男女| 999在线观看免费大全电视剧| 久久天堂av| 这里精品视频免费| 少妇人妻精品一区二区三区| 3d成人动漫网站| 欧美性受xxx黑人xyx性爽| 婷婷成人综合网| 黑人巨大精品一区二区在线| 中文字幕高清不卡| 精品成人av一区二区三区| 成人av在线看| 成年人视频网站免费观看| 欧美成人日韩| 精品久久免费观看| 日韩欧美伦理| 三区精品视频| 国产亚洲电影| 日韩av在线电影观看| 偷拍精品福利视频导航| 国产乱码精品一区二区三区卡| 精品一区二区三区在线观看视频| 国产日韩在线看片| 成人国产综合| 国产精品久久久亚洲| 日本欧美一区| 国产精品成av人在线视午夜片| 免费亚洲电影| 清纯唯美亚洲激情| 少妇视频一区| 国产成人福利视频| 日本欧美不卡| 国产精品久久综合av爱欲tv| 四虎4545www精品视频| 国产精品一区二区性色av| 成人在线高清| 国产一区玩具在线观看| 青娱乐极品盛宴一区二区| 国产在线视频2019最新视频| 成人网av.com/| 999国产在线| 国产精品调教视频| 久久久神马电影| 国产一卡不卡| 国产一区一区三区| 欧美精品色网| 亚洲高清视频一区二区| 青青草综合网| 在线观看污视频| 影音先锋国产精品| 亚洲中文字幕无码不卡电影| 久热综合在线亚洲精品| 少妇一级淫免费播放| 国产在线看一区| 黄色国产在线视频| 久久久天堂av| 男人的午夜天堂| 一区二区免费在线播放| 成年人免费看毛片| 欧美最猛性xxxxx直播| 国产精品久久久久精| 精品久久久久久久久久久久包黑料 | www日韩av| 国产欧美三级电影| 欧美日韩免费观看一区| 国产大片一区| 1024av视频| 激情综合网最新| 五月天激情小说| 国产精品三级视频| 国产精品99精品| 欧美三级日韩在线| 亚洲爱情岛论坛永久| 精品亚洲一区二区三区| av片在线看| 国模私拍视频一区| 免费成人高清在线视频| 国内外成人免费视频| 日本久久精品| 男人天堂999| 理论片日本一区| 亚洲国产精品成人综合久久久| 国产精品丝袜久久久久久app| 国产中文字幕免费| 欧美三级视频在线播放| 午夜小视频在线播放| 久久久国产视频| 欧美成人ⅴideosxxxxx| 国产91亚洲精品一区二区三区| 欧美中文一区二区| 国产精品成人久久电影| 久久精品av麻豆的观看方式| 极品人妻一区二区三区| 国产精品看片你懂得| 日本道在线观看| 欧美一级精品在线| yw193.com尤物在线| 国产亚洲一区二区在线| 不卡av免费观看| 成人在线小视频| 欧美一站二站| 粗暴91大变态调教| 本田岬高潮一区二区三区| 免费看特级毛片| 欧美优质美女网站| 久久天堂电影| 69视频在线免费观看| 99a精品视频在线观看| 青青草影院在线观看| 免费精品视频在线| 亚洲国产av一区| 狠狠躁夜夜躁人人爽超碰91| 免费观看国产视频| 久久久噜久噜久久综合| 久久久久久久久久久久电影| 亚洲午夜在线观看| 欧美a一区二区| 人妻aⅴ无码一区二区三区| 亚洲成国产人片在线观看| 性生活免费网站| 久久99精品视频一区97| 久久精品一级| 中文字幕在线乱| 九一久久久久久| 三级黄色录像视频| 欧美人妇做爰xxxⅹ性高电影| av资源种子在线观看| 国产精品美女久久久免费| 精品国产一级毛片| 日本美女高潮视频| 亚洲国产成人午夜在线一区| 亚洲中文无码av在线| 在线视频免费一区二区| 欧美aaaaaa| av动漫在线免费观看| 成人免费视频caoporn| 国产在线观看免费视频今夜| 亚洲第一级黄色片| 久草在线资源站手机版| 欧美日韩日本网| 另类的小说在线视频另类成人小视频在线 | 法国空姐在线观看免费| 国产大陆精品国产| 亚洲熟女www一区二区三区| 精品久久久影院| 国产精品yjizz视频网| 蜜桃欧美视频| 日韩av中文字幕一区二区| 农村老熟妇乱子伦视频| 555www色欧美视频| 国模雨婷捆绑高清在线| 久久久久久久久久久久久久一区| 视频一区二区不卡| 午夜免费激情视频| 亚洲精品第一国产综合精品| 欧美电影免费观看| 中文字幕日韩一区二区三区不卡| 国产成人精品影视| 亚洲午夜18毛片在线看| 深夜福利一区二区| 国产精品极品国产中出| 免费激情视频在线观看| 日韩毛片在线免费观看| 黄色美女一级片| 国产精品精品国产| 亚洲欧美伊人| 国产色视频一区二区三区qq号| 欧美精选午夜久久久乱码6080| 国产区美女在线| 午夜精品一区二区在线观看| 国产原创一区二区三区| 久久久久99精品成人片三人毛片| 日韩在线激情视频| 欧美xxxx在线| 在线观看免费视频污| 欧美性生交大片免网| av片在线观看|