半連接轉內連接 | OceanBase SQL 查詢改寫

查詢優化器是關系型數據庫系統的核心模塊,是數據庫內核開發的重點和難點,也是衡量整個數據庫系統成熟度的“試金石”。為了幫助大家更好地理解 OceanBase 查詢優化器,我們撰寫了查詢改寫系列文章,帶大家更好地掌握查詢改寫的精髓,熟悉復雜 SQL 的等價性,寫出高效的 SQL。本文將重點和大家介紹半連接轉內連接,更多文章歡迎進入【OceanBase SQL 查詢改寫專題】?查看。

引言

查詢分析中經常使用子查詢語句,數據庫為了提高子查詢的執行性能,往往會把子查詢語句改寫成半連接(子查詢提升方法參見本系列第二篇:子查詢提升首篇)。

例如,我們需要查詢2022-08-01到2022-08-02之間已排片的電影,可以通過IN子查詢檢查電影是否在排片期內。查詢SQL如Q1所示。

-- 影片表
MOVIE(movie_id primary key, movie_name, release_date)
-- 排片表
PLAY(play_id, movie_id, play_time, price, seats)Q1:
SELECT movie_name
FROM? ?movie
WHERE? movie_id IN (SELECT movie_idFROM? ?playWHERE? play_time BETWEEN DATE'2022-08-01'?AND DATE'2022-08-02');Q2:
SELECT movie_name
FROM? ?movie LEFT SEMI
JOIN? ?(SELECT movie_idFROM? ?playWHERE? play_time BETWEEN date'2022-08-01'?AND? ? date'2022-08-02' )play
ON? ? ?movie.movie_id = play.movie_id;

對于查詢Q1,OceanBase會做子查詢提升改寫,改寫成等價的查詢Q2,使用半連接來計算子查詢。對于新的查詢,優化器可以選擇hash left semi join、hash right semi join、merge left semi join、merge right semi join、nested loop left semi join五種連接算法執行。下圖展示了其中一種執行計劃。

Query Plan:?
==========================================
|ID|OPERATOR? ? ? |NAME |EST. ROWS|COST? |
------------------------------------------
|0 |HASH SEMI JOIN|? ? ?|30? ? ? ?|910000|
|1 | TABLE SCAN? ?|MOVIE|1000000? |460000|
|2 | SUBPLAN SCAN |PLAY |30? ? ? ?|46? ? |
|3 |? TABLE SCAN? |PLAY |30? ? ? ?|46? ? |
==========================================

考慮一種業務場景:movie表的數據量達100w,2022-08-01到2022-08-02之間已排片的電影約30部。上面五種連接算法都需要掃描movie表的全部數據,掃描成本比較高。而我們知道movie表的主鍵為movie_id,如果我們能夠先查詢出2022-08-01到2022-08-02之間已排片的movie_id,再去movie表查詢movie_name,就能夠使用movie表的主鍵索引,執行30次主鍵索引掃描即可完成查詢。

為了能夠按照最優計劃執行Q1查詢,我們需要以play表作為驅動表,并且使用index nested loop join的算法,把movie_id的連接條件轉換為movie表的索引掃描條件。計劃如下所示。

Query Plan:?
=====================================================
|ID|OPERATOR? ? ? ? ? ? ? ? ? ?|NAME |EST. ROWS|COST|
-----------------------------------------------------
|0 |NESTED LOOP RIGHT SEMI JOIN|? ? ?|30? ? ? ?|91? |
|1 | SUBPLAN SCAN? ? ? ? ? ? ? |PLAY |30? ? ? ?|96? |
|2 |? TABLE SCAN? ? ? ? ? ? ? ?|PLAY |30? ? ? ?|96? |
|3 | TABLE GET? ? ? ? ? ? ? ? ?|MOVIE|1? ? ? ? |46? |
=====================================================

但我們知道,數據庫沒有NESTED LOOP RIGHT SEMI JOIN的算法實現,那我們要怎樣改寫這條SQL,使數據庫能夠支持這種優化計劃呢?為此,OceanBase引入了一個改寫規則:半連接轉內連接,將滿足一定條件的半連接查詢轉換為內連接查詢,優化器就可以針對上述場景生成最優的index nested loop join計劃。

半連接轉內連接

介紹半連接轉內連接規則前,我們先了解下半連接的執行邏輯。還是以Q1為例進行說明,從movie表中讀取一行數據,然后從play表內查找指定movie_id的數據,如果存在,則執行數據,否則不輸出。從描述中我們可以知道,對于movie表中給定的一行數據,無論play表存在多少條數據與指定的movie_id相同,查詢都只輸出一行數據。

而內連接對于符合條件的每一條數據都會輸出,也就是說,如果半連接直接轉內連接,執行結果可能會重復輸出多次。為了保證改寫不改變查詢語義,我們需要對play的movie_id去重,保證movie表的每行數據在play表中只匹配一行數據,改寫后的查詢如Q3所示。

Q3:
SELECT movie_name
FROM? ?movie INNER JOIN
JOIN? ?(SELECT DISTINCT movie_idFROM? ?playWHERE? play_time BETWEEN date'2022-08-01'?AND? ? date'2022-08-02' )play
ON? ? ?movie.movie_id = play.movie_id;

對于新的查詢Q3,優化器可以嘗試movie hash join play、play hash join movie、movie merge join play、 play merge join movie、movie nested loop join play、play nested loop join movie這六種連接算法執行,比原來多了一種。此時,優化器可以生成之前描述的最優計劃。

================================================
|ID|OPERATOR? ? ? ? ? ? ? |NAME |EST. ROWS|COST|
------------------------------------------------
|0 |NESTED-LOOP JOIN? ? ? |? ? ?|30? ? ? ?|46? |
|1 | SUBPLAN SCAN? ? ? ? ?|PLAY |30? ? ? ?|46? |
|2 |? MERGE DISTINCT? ? ? |? ? ?|30? ? ? ?|46? |
|3 |? ?SORT? ? ? ? ? ? ? ?|? ? ?|30? ? ? ?|46? |
|4 |? ? TABLE SCAN? ? ? ? |PLAY |30? ? ? ?|46? |
|5 | TABLE GET? ? ? ? ? ? |MOVIE|1? ? ? ? |7? ?|
================================================

注意到改寫之后的查詢比原來的查詢多了一次去重計算,Q3查詢并不是在所有場景下都比Q2查詢更優,因此,OceanBase的半連接轉內連接改寫是一種基于代價的改寫,即優化器會對比改寫前后最優計劃的代價,如果代價降低了,才會應用改寫,否則不會改寫查詢。

優化點

上文我們介紹了半連接轉內連接主要是增加去重計算來保證語義的正確性,也正因為增加了去重計算,改寫之后的查詢并不總是比改寫之前的查詢更優。

我們可以思考一下,是否所有場景都需要加去重計算?答案是否定的,在有些場景下,我們可以把半連接直接轉成內連接,例如:play表的movie_id本身就有唯一約束,或者play表只有一行數據滿足條件。在這些場景下,我們可以不添加去重計算,這也意味著改寫之后的查詢總是比改寫之前的查詢更優,不需要額外比較代價。

改寫陷阱

在之前的介紹中,我們沒有說明數據類型對改寫規則的影響,實際上半連接轉內連接對數據類型是有要求的。通過一個例子說明,對于查詢Q4,如果需要改寫成內連接,改寫的SQL如Q5所示。

create table t1(c1 int);
insert into t1 values(0);
create table t2(c1 varchar(20));
insert into t2 values('0.0');
insert into t2 values('0.1');Q4:
SELECT *
FROM? ?t1
WHERE? c1 IN (SELECT c1FROM? ?t2);?
Q5:
SELECT t1.c1
FROM? ?t1INNER JOIN (SELECT DISTINCT c1FROM? ?t2)t2ON t1.c1 = t2.c1;?

上面的改寫正確嗎?對于Q4,結果是一行數據:0,對于Q5,結果是兩行數據:0,?0。為什么呢?在對t2表的c1列去重時,使用的是varchar(20)類型,'0.0'與'0.1'屬于不同的數據,不會發生去重操作,與t1表連接時需要把varchar(20)類型的數據轉換成int類型比較,此時'0.0'與'0.1'轉換成了0與0,導致執行結果不正確。

為了避免數據類型影響改寫的正確性,我們需要在改寫時,對數據類型做適當的處理,你可以思考一下怎樣是正確的改寫查詢。

總結

本文主要介紹OceanBase的半連接轉內連接改寫,以及這個改寫的優化點、容易被忽略的錯誤。OceanBase會把滿足一定條件的半連接轉換成內連接,使優化器能夠嘗試更多的計劃,生成的查詢計劃可能更優。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/63541.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63541.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63541.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

android opencv導入進行編譯

1、直接新建module進行導入,選擇opencv的sdk 導入module模式,選擇下載好的sdk,修改module name為OpenCV490。 有報錯直接解決報錯,沒報錯直接運行成功。 2、解決錯誤,同步成功 一般報錯是gradle版本問題較多。我的報…

通過阿里云 Milvus 與 PAI 搭建高效的檢索增強對話系統

背景介紹 阿里云向量檢索服務Milvus版(簡稱阿里云Milvus)是一款云上全托管服務,確保了了與開源Milvus的100%兼容性,并支持無縫遷移。在開源版本的基礎上增強了可擴展性,能提供大規模 AI 向量數據的相似性檢索服務。相…

【批量生成WORD和PDF文件】根據表格內容和模板文件批量創建word文件,一次性生成多個word文檔和批量創建PDF文件

如何按照Word模板和表格的數據快速制作5000個word文檔 ? 在與客戶的合作的中需要創建大量的合同,這些合同的模板大概都是一致的,是不是每次我們都需要填充不一樣的數據來完成? 今天用表格數據完成合同模板的填充,批量…

pip使用方法

1. 安裝包: pip install :安裝指定的 Python 包。 pip install :安裝特定版本的 Python 包。 pip install -r requirements.txt:從文件中讀取依賴列表并安裝所有列出的包。 pip install --pre :允許安裝預發布或開發版…

Windows11 安裝 Ubuntu-20.04,同時安裝配置 zsh shell,配置 git 別名(alias),大大提高開發效率

背景:家里配置了一臺 Windows 電腦,有時候需要用到 vscode 開發測試一些代碼,在使用過程中發現原生 windows 敲代碼不是很友好,于是想到配置 wsl,安裝 Ubuntu,并安裝配置 zsh shell,同時配置 gi…

什么是漸進式 Web 應用,有哪些特點

漸進式 Web 應用 (Progressive Web Apps, PWAs) 的定義與特點 一、定義 漸進式 Web 應用(Progressive Web App,簡稱 PWA)是一種結合了傳統 Web 技術和現代移動應用特性的新型應用程序形式。PWAs 可以像普通網站一樣通過瀏覽器訪問&#xff…

鴻蒙心路旅程:HarmonyOS NEXT 心路旅程:技術、成長與未來

HarmonyOS NEXT 心路旅程:技術、成長與未來 技術的浪潮中,總有一些瞬間讓人感到心潮澎湃。作為一名HarmonyOS NEXT開發者,我有幸成為這個時代科技創新的一部分。從最初的接觸到深入學習、開發,以及如今規劃未來的職業方向&#x…

勤研低代碼平臺:重塑軟件開發協作新生態

在當今數字化浪潮洶涌澎湃的時代,軟件開發的效率與質量成為企業競爭的關鍵因素之一。勤研低代碼開發平臺以創新性的實際頁面 - 功能設計 - 頁面設計 - 原型頁面切換功能,脫穎而出,為軟件開發過程中的團隊協作、客戶溝通以及項目推進帶來了前所…

ChatGPT等大語言模型與水文水資源、水環境領域的深度融合

聚焦GPT等大語言模型與水文水資源領域的深度融合,通過系統化內容與實踐案例,講解如何高效完成時間序列分析、空間數據處理、水文模型優化以及智能科學寫作等任務。同時,展示AI在高級機器學習模型開發、資源優化算法編程與模型微調中的最新應用…

node安裝,npm安裝,vue-cli安裝以及element-ui配置項目

node.js Node.js主要用于開發高性能、高并發的網絡服務器,特別適合構建HTTP服務器、實時交互應用(如聊天室)和RESTful API服務器等。?它使用JavaScript語言,基于Chrome V8引擎,提供模塊化開發和豐富的npm生態系統&…

easyplayer-pro播放器學習

背調 查詢官方文檔,EasyPlayer-pro支持ws-flv, http-flv, hls, webrtc(webrtc://xxx)格式,電子放大、水印(動態水印、幽靈水印)、顯示上一個視頻最后一幀、播放器快照截圖、視頻錄制(WebM格式(音頻視頻)、MP4格式(視頻),FLV格式(…

5G 模組 初始化狀態檢測

5G 模組 上電檢測 5G 模組 上電檢測 #終端上電后,待模組正常啟動,再進入 控制臺。 #vim /etc/profile##新增 until [ -c /dev/ttyUSB1 ] doecho -e "Wait module[5G] up ... "sleep 5 done ##新增The End.

WPF+MVVM案例實戰與特效(四十三)- 打造動態炫酷彩虹字控件,讓你的界面動起來

文章目錄 1、引言1、案例效果2、案例實現1、XAML 布局2、邏輯代碼3、動畫效果4、控件使用5、運行效果3、案例源代碼4、總結1、引言 上一節,我們實現了炫酷的彩虹字控件,現在我們想讓彩虹字更加生動吸引人,讓每個字體跳動起來,讓字體活過來。這里我們通過動畫實現,我們把這…

線程知識總結(一)

1、概述 1.1 進程與線程 進程是程序運行時,操作系統進行資源分配的最小單位,包括 CPU、內存空間、磁盤 IO 等。從另一個角度講,進程是程序在設備(計算機、手機等)上的一次執行活動,或者說是正在運行中的程…

深入QML語法

文章目錄 深入了解 QML 文檔的結構和語法什么是 QML 文檔?導入語句導入語句的格式示例 對象聲明基本語法示例更復雜的對象聲明 QML 對象類型詳解1. Rectangle(矩形)2. Gradient(漸變)3. Text(文本&#xff…

【Python】使用Selenium 操作瀏覽器 自動化測試 記錄

【自動化】Python SeleniumUtil 工具 開啟開發者模式 自動安裝油猴用戶腳本等-CSDN博客文章瀏覽閱讀389次。【自動化】Python SeleniumUtil 工具。https://blog.csdn.net/G971005287W/article/details/144565691?spm1001.2014.3001.5501【學習記錄】瀏覽器指紋相關學習記錄&am…

Linux應用軟件編程-文件操作(標準io)

在Linux下一切皆文件,比如:.txt,.c,.h,.jpg,目錄,鍵盤,鼠標,顯示器、硬盤等等都是文件,即IO。文件操作的統一思想:打開文件,讀、寫文件…

【Rust自學】4.4. 引用與借用

4.4.0 寫在正文之前 這一節的內容其實就相當于C的智能指針移動語義在編譯器層面做了一些約束。Rust中引用的寫法通過編譯器的約束寫成了C中最理想、最規范的指針寫法。所以學過C的人對這一章肯定會非常熟悉。 喜歡的話別忘了點贊、收藏加關注哦(加關注即可閱讀全文…

深入解析 StarRocks 物化視圖:全方位的查詢改寫機制

小編導讀: 本文將重點介紹如何利用物化視圖進行查詢改寫。文章將全面介紹物化視圖的基本原理、關鍵特性、應用案例、使用場景、代碼細節以及主流大數據產品的物化視圖改寫能力對比。 物化視圖在 StarRocks 中扮演著至關重要的角色,它是進行數據建模和加速…

2. petalinux-build失敗

NOTE 解決因為網絡原因產生的編譯錯誤分享詳細的解決步驟 報錯的情況 因為網絡原因產生編譯錯誤 現象 找不到適合的包文件(No suitable stageing package found) 不能發現文件(Fetcher failure for URL) 解決方法 采用本地加載本地文件的方式,步驟如下 進入…