主頁 > 後端開發 > Hive使用Calcite CBO優化流程及SQL優化實戰

Hive使用Calcite CBO優化流程及SQL優化實戰

2020-09-22 21:53:12 後端開發

目錄
  • Hive SQL執行流程
    • Hive debug簡單介紹
    • Hive SQL執行流程
  • Hive 使用Calcite優化
    • Hive Calcite優化流程
    • Hive Calcite使用細則
      • Hive向Calcite提供元資料

上一篇主要對Calcite的背景,技術特點,SQL的RBO和CBO等做了一個初步的介紹,深入淺出Calcite與SQL CBO(Cost-Based Optimizer)優化

這一篇會從Hive入手,介紹Hive如何使用Calcite來優化自己的SQL,主要從原始碼的角度進行介紹,文末附有一篇其他博主的文章,從其他角度闡述Hive CBO的,可供參考,

另外,上一篇中有提到我整理了Calcite的各種樣例,Calcite的一些使用樣例整理成到github,https://github.com/shezhiming/calcite-demo,其中自定義rule,Relnode等內容有部分參照自Hive,在介紹的時候可能也會稍微講到,

最后會從Hive這個例子延伸,看看自己可以怎么借助Calcite來優化SQL,

Hive SQL執行流程

Hive debug簡單介紹

在開始介紹之前,本著授人以漁的精深,先說下如何使用Hive debug查看原始碼執行流程,具體流程可以參照這篇:

  • hive原始碼決議之本地環境搭建

簡單說就是搭建個hive環境,通過 hive --debug -hiveconf hive.root.logger=DEBUG,console陳述句開啟 debug 模式,開啟后 hive 會監聽 8000 埠并等待輸入,此時從本地的 hive 原始碼專案中配置遠程 debug 就可以通過 debug 的方式追蹤 hive 執行流程,

debug程序中,執行SQL的入口是在CliDriver.executeDriver()這個方法,可以在這個地方打一個斷點,然后就可以除錯跟蹤了,如下圖:

hive原始碼入口

搭建hive服務的話,建議使用docker,搭建起來會比較方便一些,

PS:這里介紹用的Hive的版本是2.3.x,

Hive SQL執行流程

前面說到,debug輸入陳述句的入口的類是org.apache.hadoop.hive.cli.CliDriver,而實際執行SQL陳述句邏輯的主要模塊是ql(Query Language) 模塊的Driver類(org.apache.hadoop.hive.ql.Driver),Driver主要邏輯,是先呼叫compile(String command, boolean resetTaskIds, boolean deferClose)方法,對 SQL 進行編譯,然后Driver呼叫execute()方法,執行對應的MR任務,我們的關注點主要放在compile()方法的執行程序,

compile()方法中,整個SQL執行流程如下圖:
Hive SQL執行流程

即先將SQL決議成AST Node,然后轉換成QB,再轉換成Operator tree,最后進行邏輯優化和物理優化后,就編程一個可執行的MR任務了,對應階段的入口,我也在上面的圖中標注出來了,

其中較為核心的,從AST Node到Phsical Optimize這幾個階段,都是在SemanticAnalyzer.analyzeInternal()方法中進行的,這個方法中的注釋已經跟我們說明了SQL執行的主要流程,我這里貼一下:

  1. Generate Resolved Parse tree from syntax tree
  2. Gen OP Tree from resolved Parse Tree
  3. Deduce Resultset Schema
  4. Generate Parse Context for Optimizer & Physical compiler
  5. Take care of view creation
  6. Generate table access stats if required
  7. Perform Logical optimization
  8. Generate column access stats if required - wait until column pruning takes place during optimization
  9. Optimize Physical op tree & Translate to target execution engine (MR, TEZ..)
  10. put accessed columns to readEntity
  11. if desired check we're not going over partition scan limits

大致的流程和圖里面介紹的差不多,不過會多一些細節上的補充,感興趣的童鞋可以實際執行一下看看執行流程,我這里簡單介紹下,前幾個步驟就是根據AST Node生成QB,然后再轉換成Operator Tree,然后處理視圖和生成統計資訊,最后執行邏輯優化和物理優化并生成MapReduce Task,

上述流程有一個比較容易讓人疑惑的點,無論是AST Node,Operator Tree都比較好理解,后面的邏輯優化和物理優化也都是SQL決議的常規套路,但為什么中間會插入一個QB的階段?

其實這里插入一個QB,一個主要的目的,是為了讓Calcite來進行優化,

Hive 使用Calcite優化

Hive Calcite優化流程

在Hive中,使用Calcite來進行核心優化,它將AST Node轉換成QB,又將QB轉換成Calcite的RelNode,在Calcite優化完成后,又會將RelNode轉換成Operator Tree,說起來很簡單,但這又是一條很長的呼叫鏈,

Calcite優化的主要類是CalcitePlanner,更加細節點,是在CalcitePlannerAction.apply()這個方法,CalcitePlannerAction是一個內部類,包括將QB轉換成RelNode,優化具體操作都是在這個方法中進行的,

這個方法的注釋也給出了主要操作步驟,這里也貼一下流程:

  1. Gen Calcite Plan
  2. Apply pre-join order optimizations
  3. Apply join order optimizations: reordering MST algorithm
    If join optimizations failed because of missing stats, we continue with the rest of optimizations
  4. Run other optimizations that do not need stats
  5. Materialized view based rewriting
    We disable it for CTAS and MV creation queries (trying to avoid any problem due to data freshness)
  6. Run aggregate-join transpose (cost based)
    If it failed because of missing stats, we continue with the rest of optimizations
    7.convert Join + GBy to semijoin
  7. Run rule to fix windowing issue when it is done over aggregation columns
  8. Apply Druid transformation rules
  9. Run rules to aid in translation from Calcite tree to Hive tree
    10.1. Merge join into multijoin operators (if possible)
    10.2. Introduce exchange operators below join/multijoin operators

簡單說下,就是先生成RelNode(根據QB),然后進行一系列的優化,這里的優化最主要的還是跟join有關的優化,上面流程步驟中的2~7步都是join相關的優化,然后才是根據各個rule進行優化,最后再轉換成Operator Tree,這就是最上面圖片中QB->Operator Tree的流程,

接下來我們就深入這個流程,看看Hive是如何使用Calcite做SQL優化的,

Hive Calcite使用細則

要介紹Hive如何利用Calcite做優化,我們還是先轉頭看看Calcite優化需要哪些東西,先貼一下上一篇中介紹到的,Calcite的架構圖:
Calcite架構

從圖中可以明顯發現,跟QUery Optimizer(優化器)有關的模塊有三個,Operator ExpressionsMetadata ProvidersPluggable Rules,三者分別是關系表達樹(由RelNode節點組成),元資料提供器,還有Rule,

其中關系表達樹是Calcite將SQL決議校驗后產生的一種關系樹,樹的節點即是RelNode(關系代數節點),RelNode又有多種型別,比如TableScan代表最底層的表輸入,Filter表示Where(關系代數的過濾),Project表示select(關系代數的投影),即大部分的RelNode都會和關系代數中的操作對應,以一條SQL為例,一條簡單的SQL編程RelNode就會是下面這個樣子:

select * from TEST_CSV.TEST01 where TEST01.NAME1='hello';

//RelNode關系樹
Project(ID=[$0], NAME1=[$1], NAME2=[$2])
  Filter(condition=[=($1, 'hello')])
    TableScan(table=[[TEST_CSV, TEST01]])

再來說說元資料提供器,所謂元資料,就是跟表有關的那些資訊,rowcount,表欄位等資訊,其中rowcount這類資訊跟計算cost有關,Calcite有自己的默認的元資料提供器,但做的比較粗糙,如果有需要應該自己提供一個元資料提供器提供自己的元資料資訊,

最后就是Rules,這塊Calcite默認已經有非常多的Rules,當然我們也可以定義自己的Rule再添加進去,不過通常基本的SQL優化使用Calcite的Rule就足夠,這里說下怎么在idea里面查看Calcite提供的Rule,先找到RelOptRule這個類,然后按下查看類繼承關系的快捷鍵(Mac上是Ctrl+h),就能看到多條Rule,如果要自己實作也可以照著其中實作,

稍微總結一下,Calcite已經基本提供了所需要的Rule,所以要使用Calcite優化SQL,我們需要的,是提供SQL對應的RelNode,以及通過元資料提供器提供自身的元資料,

Hive要使用Calcite優化,也無外乎就是提供上述的兩部分內容,

用過Hive的童鞋應該知道,Hive可以通過外部存盤組件存盤資料庫和表元資料資訊,包括rowcount,input size等(需要執行Analyze陳述句或DML才會計算并元資料到Mysql),Hive要做的就是將這些資訊,提供給Calcite,

Hive向Calcite提供元資料

需要先明確的一點是,元資料提供器需要提供的一個比較重要的資料,是rowcount,在進行CBO計算Cost的程序中,CPU,IO等資訊也基本都是從rowcount加工而來的,且元資料重要的一個用途,也是進行CBO優化,輸入的元資料可以等價于CBO要用到的Cost資料,

繼續深入CBO的Cost,通過前面的例子,可以知道SQL在Calcite會被決議成RelNode樹,RelNode樹上層節點(Project等)的Cost資訊,是由下層的資訊計算而得到的,我們的目標是要自定義Cost資訊,那么就需要將Hive的元資料注入最底層的TableScan的Cost資訊,同時要能夠自定義每個節點的Cost計算方式

還記得前面說到Calcite默認的元資料提供器比較粗糙嗎,就是體現在它的TableScan的rowcount默認是100,而每個節點的計算邏輯也比較簡單,

所以重點有兩個,一個是最底層TableScan的cost資訊注入方式,另一個是如何每種RelNode型別定義計算邏輯的方式

辦法有兩種,一種是比較上層的,通過自定義RelNode,修改其中的computeSelfCost()方法和estimateRowCount方法,這兩個方法,一個是計算Cost資訊,另一個是計算行數,這種辦法可以直接解決TableScan的cost注入,和自定義每種RelNode型別的計算邏輯,但這種辦法忽了元資料提供器,算是比較簡單粗暴的方法,

就像這樣:

代碼見:https://github.com/shezhiming/calcite-demo/blob/master/src/main/java/pers/shezm/calcite/optimizer/reloperators/CSVTableScan.java

public class CSVTableScan extends TableScan implements CSVRel {
    private RelOptCost cost;
    public CSVTableScan(RelOptCluster cluster, RelTraitSet traitSet, RelOptTable table) {
        super(cluster, traitSet, table);
    }

    @Override public double estimateRowCount(RelMetadataQuery mq) {
        return 50;
    }

    @Override
    public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
        //return super.computeSelfCo(planner, mq);

        if (cost != null) {
            return cost;
        }
        //通過工廠生成 RelOptCost ,注入自定義 cost 值并回傳
        cost = planner.getCostFactory().makeCost(1, 1, 0);
        return cost;
    }
}

另一種方法則更加底層一些,TableScan的元資料資訊,是通過內部變數RelOptTable獲取,那么就自定義RelOptTable實作元資料注入,然后通過實作MetadataDef<BuiltInMetadata.RowCount>系列的介面,在其中添加自己的計算邏輯,將這些自定義的類都加載到RelMetadataProvider中(元資料提供器,可以在其中提供自定義的元資料和計算邏輯),再注入到Calcite中就可以實作自己的Cost計算邏輯,這也是Hive的實作方式,

我們從TableScan注入,和RelMetadataProvider這兩方面看看Hive是怎么做,

TableScan的注入元資料

首先,Hive自定義了Calcite的TableScan,在org.apache.hadoop.hive.ql.optimizer.calcite.reloperators.HiveTableScan,但這里并不涉及元資料,我們觀察下TableScan的原始碼,

public abstract class TableScan extends AbstractRelNode {
  //~ Instance fields --------------------------------------------------------

  /**
   * The table definition.
   */
  protected final RelOptTable table;

  //生成 cost 資訊
  @Override public RelOptCost computeSelfCost(RelOptPlanner planner,
      RelMetadataQuery mq) {
    double dRows = table.getRowCount();
    double dCpu = dRows + 1; // ensure non-zero cost
    double dIo = 0;
    return planner.getCostFactory().makeCost(dRows, dCpu, dIo);
  }

  //生成 rowcount 資訊
  @Override public double estimateRowCount(RelMetadataQuery mq) {
    return table.getRowCount();
  }
}

順便說下,上面說過,Cost資訊和rowcount息息相關,這里就可以看出來了,Cpu直接就用rowcount加一,并且這里也可以看出默認的元資料提供器比較粗糙,

不過我們重點不在這,通過代碼可以發現它主要是通過table這個變數獲取表元資料資訊,而hive也自定義了相關的類,就是繼承自RelOptTableRelOptHiveTable,這個類在HiveTableScan初始化的時候,會作為引數傳遞進去,而它的元資料則是通過QB獲取,這個程序也是在CalcitePlannerAction.apply()中完成的,至于QB的元資料,則是在初始化的時候通過Mysql獲取到的,聽起來挺繞,稍微按順序整理下:

  1. QB初始化的時候,通過Mysql獲取元資料資訊并注入
  2. QB轉成RelNode的時候,將元資料傳遞到RelOptHiveTable
  3. RelOptHiveTable作為引數新建HiveTableScan

以上就是Hive完成TableScan元資料注入的程序,
自定義RelMetadataProvider
再來說說如何提供RelMetadataProvider,這個主要是通過繼承MetadataHandler實作的,這里貼一下就能清楚metadata有哪些型別,以及Hive實作了哪些:

Hive metadata

這里可以清楚看到,metadata除了之前提到的rowcount,cost,還有size,Distribution等等,其中白色的就是Hive實作的,

而之前一直提到的rowcount和cost,對應的就是HiveRelMdRowCountHiveRelMdCost(這個真正的cost模型實作,是在HiveCostModel),這里貼一下HiveCostModel中Join的Cost自定義計算邏輯,因為join優化是一個重點,所以這里會根據不同實作類去計算cost,相比Calcite默認實作,精細很多了,

public abstract class HiveCostModel {
  ......其他代碼
  public RelOptCost getJoinCost(HiveJoin join) {
    // Select algorithm with min cost
    JoinAlgorithm joinAlgorithm = null;
    RelOptCost minJoinCost = null;

    if (LOG.isTraceEnabled()) {
      LOG.trace("Join algorithm selection for:\n" + RelOptUtil.toString(join));
    }

    for (JoinAlgorithm possibleAlgorithm : this.joinAlgorithms) {
      if (!possibleAlgorithm.isExecutable(join)) {
        continue;
      }
      RelOptCost joinCost = possibleAlgorithm.getCost(join);
      if (LOG.isTraceEnabled()) {
        LOG.trace(possibleAlgorithm + " cost: " + joinCost);
      }
      if (minJoinCost == null || joinCost.isLt(minJoinCost) ) {
        joinAlgorithm = possibleAlgorithm;
        minJoinCost = joinCost;
      }
    }

    if (LOG.isTraceEnabled()) {
      LOG.trace(joinAlgorithm + " selected");
    }

    join.setJoinAlgorithm(joinAlgorithm);
    join.setJoinCost(minJoinCost);

    return minJoinCost;
  }
  ......其他代碼
}

其他的也和這個差不多,就是更加精細的自定義Cost計算,就不多展示了,

OK,說完上面這些,Hive的優化也就差不多介紹完了,這里重點還是介紹了Hive如何向Calcite中注入元資料資訊以及實作自定義的RelNode計算邏輯,至于Calcite進行RBO和CBO優化的更多細節,我上一篇有提到,也有給出相關資料,這里就不多介紹,

深入淺出Calcite與SQL CBO(Cost-Based Optimizer)優化

還有另一個點是撰寫自定義的rule實作自定義優化,這一點以后與機會再說,

另外我最上方的github中,也有簡單照著hive,實作了自己注入元資料和自定義RelNode的計算方式,基本都是從最簡單的CSV的例子延伸而言,方便理解,有興趣的朋友可以看看,如果有幫助不妨點個star,

以上~

參考文章:
Apache Hive 是怎樣做基于代價的優化的?

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/107539.html

標籤:其他

上一篇:性能測驗-Locust分布式執行

下一篇:404左葉子之和

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more