怎樣簡單實現不同數據庫的表間的 JOIN 運算

數據分析涉及不同業務系統時就要做跨庫計算,而表間 JOIN 是最麻煩的,很多數據庫都不具備這樣的能力,用 Java 取數再計算又太復雜。用 esProc 完成跨庫 JOIN 會簡單很多。

數據與用例

車輛管理系統(DB_Vehicle)保存了車輛與車主等相關信息,其中車主信息表 owner_info 表結構簡化如下:

..

主鍵 owner_id 是車主身份證號。

車輛表 vehicle_master 簡化結構如下:

..

vin 設為主鍵,plate_no 也是唯一的,兩個字段在邏輯上都可以視為主鍵。

交管系統(DB_Traffic)存儲了車輛交通信息,其中違章記錄表 traffic_violation 結構如下:

..

公民信息系統(DB_CitizenEvent)存儲了公民相關信息,其中公民事件表 citizen_event 結構如下:

..

4 個表間邏輯關系簡單描述是這樣的:

..

從邏輯上看,citizen_event 是 owner_info 是多對一的關系,作為維表的 owner_info 的規模要遠小于 citizen_event。

traffic_violation 和 vehicle_master 這兩個表也是一對多的關系,規模都可能很大,從后者的角度來看,traffic 更像一個子表,這兩個表構成主子關系(plato_no 是 vehicle 表的邏輯主鍵)。

為什么要區分表間關系呢?

日常的等值 JOIN 基本都會涉及主鍵(多對多的關聯基本沒有業務意義),大體可以分為兩種:維表關聯是一種,是普通字段和維表的主鍵關聯(如 citizen_event 和 owner_info);另一種是某個表的主鍵與另一個表的主鍵或部分主鍵的關聯(如 vehicle_master 和 traffic_violation,traffic_violation 表中,可以把 plate_no 和 violation_id 視為共同主鍵,即 violation_id 是從屬于 plate_no 的)。

esProc 在做 JOIN 運算時會根據不同的關聯情況選擇不同的方法,簡化編碼的同時還能提升計算效率。這里先有個印象就可以,來看具體例子。

要做這樣幾個計算:

1. 按城市統計最近一年有車公民的事件數量,用于分析各城市有車人的“行為活躍度”
2. 找出近一年獲得表彰(Commendation)的車主姓名和事件描述,用以識別“優秀市民”
3. 按年份和品牌統計車輛違章次數,用于分析某些品牌的車是否更容易違章,用于駕駛行為和車輛品牌的關聯研究

如果這些表在同一個數據庫,用 SQL 寫這些運算并不困難,大概是這樣:

1. SELECT   o.city, COUNT(e.event_id) AS event_count
FROM     citizen_event e
JOIN     owner_info o ON e.citizen_id = o.citizen_id
WHERE    e.event_time >= DATE_SUB(CURDATE(), INTERVAL 1 YEAR)
GROUP BY o.city
ORDER BY event_count DESC;2. SELECT   o.name AS citizen_name, e.description
FROM     citizen_event e
JOIN     owner_info o ON e.citizen_id = o.citizen_id
WHERE    e.event_type = 'Commendation'AND    e.event_time >= DATE_SUB(CURDATE(), INTERVAL 1 YEAR);3. SELECT   YEAR(v.violate_time) AS year, vi.brand, COUNT(v.violation_id) AS violation_count
FROM     traffic_violation v
JOIN     vehicle_info vi ON v.plate_no = vi.plate_no
GROUP BY YEAR(v.violate_time), vi.brand
ORDER BY year, violation_count DESC;

但如果跨庫時就麻煩很多了。

安裝 esProc

先通過點擊下載免費的esProc標準版?

安裝后,配數據庫連接,這里三個數據庫都是 MySQL。

先把 MySQL JDBC 驅動包放到 [esProc 安裝目錄]\common\jdbc 目錄下(其他數據庫類似)。

..

然后啟動 esProc IDE,菜單欄選擇 Tool-Connect to Data Source,配置 MySQL 標準 JDBC 連接。

..

三個數據庫都采用如上方式配置,配置完成后,測試一下連接,點擊 Connect,發現剛剛配置的兩個數據源變成粉紅色證明連接成功。

..

測試一下,按 ctrl+F9 執行腳本,可以正常查詢數據說明配置沒問題

..

用例實現

下面來實現前面第一個計算需求:按城市統計最近一年有車公民的事件數量。要關聯 owner_info 和 citizen_event 兩個表,也就是維表的關聯計算。

維表的關聯

esProc 實現:

A
1=connect("vehicle")
2=A1.query@x("select * from owner_info").keys@i(owner_id)
3=connect("citizen")
4=A3.query@x("select * from citizen_event where event_time >= DATE_SUB(CURDATE(), INTERVAL 1 YEAR)")
5=A4.switch(citizen_id,A2)
6=A5.groups(citizen_id.reg_city;count(event_id):ent)

A2 從 vehicle 庫查詢車主信息,query@x 表示數據全部加載內存后關閉數據庫連接,使用 keys@i 設置主鍵并建立索引,通常事實表會遠大于維表,這個索引會被復用很多次,能加快計算速度。

A4 查詢事件表,篩選最近一年的數據,都讀入內存。

A5 使用 switch 進行外鍵關聯。由于外鍵指向的維表記錄是唯一的,switch 直接將關聯字段 citizen_id 轉換成 A2 中的記錄(實際在內存中存儲的是維表記錄所在地址)。

..

這種轉換是一次性的,后續可以重復使用,而且可以同時處理多個維表的外鍵關聯。關聯完成后通過“關聯字段. 維表字段”方式就能引用任意維表字段。A6 就通過 citizen_id.reg_city 獲得注冊地進行分組匯總。

整體運行如下:

..

接下來繼續:找出近一年獲得表彰的車主姓名和事件描述

在前面代碼的基礎上增加:

A
7=A5.select(event_type=="Commendation").new(citizen_id.name,description)

還是基于 A5 的關聯結果進行計算,實現了復用。

..

這里我們再解釋一下,跨庫關聯很多數據庫本身就做不了,尤其是異構的情況。esProc 的這種關聯能力是與數據源無關的,什么庫都可以,甚至其他五花八門的數據源也都沒問題,這是其一。其二是,即使與單庫 JOIN 相比,esProc 顯著區分外鍵關系也有很大的好處。

書寫和理解上,通過點(.)操作符(類似對象. 屬性)就能引用外鍵表的所有字段,有多少層都可以(維表還可能有維表),也很容易表達自關聯 / 循環關聯的情況。

當 citizen_event 表的數據量很大時,用 esProc 仍然可以處理。不過,當數據量大到無法全部放進內存時,內存地址化方法就不再有效了,因為在外存無法保存事先算好的地址,這時就只能邊讀入邊地址化。

按城市統計所有車公民的事件數量:

A
1=connect("vehicle")
2=A1.query@x("select * from owner_info").keys@i(owner_id)
3=connect("citizen")
4=A3.cursor@x("select * from citizen_event")
5=A4.switch(citizen_id,A2)
6=A5.groups(citizen_id.reg_city;count(event_id):ent)

與全內存的寫法大部分一樣,區別在 A4 使用 cursor 創建游標分批讀取數據。esProc 的游標是延遲游標,附加在游標上的計算等到最后取數時才會真正計算。

..

但游標是一次性的,如果想再進行其他計算,比如還要獲得表彰的車主。再基于 A5 計算是得不到結果的(注意 A7 的計算結果):

..

這時可以使用 esProc 提供的管道機制:

AB
1=connect("dba")
2=A1.cursor@x("SELECT * FROM orders WHERE EXTRACT(YEAR FROM order_date) = EXTRACT(YEAR FROM CURRENT_DATE) ORDER BY customer_id")
3=connect("dbc")
4=A3.query@x("SELECT * FROM customer").keys@i(customer_id)
5=A2.switch(customer_id,A4)
6cursor A5=A6.groups(customer_id.customer_level;count(1):order_count)
7cursor=A7.group(customer_id).select(~.len()>1).conj().id(customer_id.customer_name)

A6 和 A7 基于 A5 創建管道(A7 是簡化寫法),B6 基于管道進行分組匯總,結果返回給 A6:

..

B7 則根據另一個管道篩選獲得表彰的數據,A7 的結果:

..

主子表的關聯

按年份和品牌統計車輛違章次數

A
1=connect("vehicle")
2=A1.query@x("select * from vehicle_master")
3=connect("traffic")
4=A3.query@x("select * from traffic_violation")
5=join(A2:v,plate_no;A4:t,plate_no)
6=A5.groups(year(t.violate_time),v.brand;count(1):cnt)

A5 使用 join 函數根據 plate_no 關聯了兩個表,其關聯結果是這樣的:

..

保留了兩邊完整記錄的多層集合,點開可以看到

..

關聯完成后,A6 就能通過多層引用進行分組匯總。

..

處理主子表關聯時,我們使用了與外鍵關聯 switch 不同的 join 函數,join 函數提供了一些選項,@1 表示左連接,@f 表示全連接,@d 做差集等,用來滿足不同的連接需求。事實上,外鍵關聯也可以使用 join 函數來完成。

那為什么不統一用 join 呢?

這里我們看到的都是兩個表關聯,如果存在多個維表(大部分情況),使用 switch 可以將維表(維表可能還有維表)都附加到事實表上,但用 join 就很難表達這種層次關系,書寫也不方便。

主子表關聯時的兩個表可能都很大,利用表的關聯字段都是主鍵(或部分主鍵)的特性,可以采用有序歸并的算法一次遍歷就完成關聯。

按年份和品牌統計車輛違章次數:

A
1=connect("vehicle")
2=A1.cursor@x("select * from vehicle_master order by plate_no")
3=connect("traffic")
4=A3.cursor@x("select * from traffic_violation order by plate_no")
5=joinx(A2:v,plate_no;A4:t,plate_no)
6=A5.groups(year(t.violate_time),v.brand;count(1):cnt)

A2 和 A4 使用 cursor 創建游標,里面的 SQL 都對 plate_no 排序。

A5 使用 joinx 做有序歸并,返回的仍是游標。剩下的代碼就跟全內存時一樣了。

有序遍歷利用了關聯鍵有序的特性,只適用于主子表的關聯(可對主鍵有序),但不適用于前面那種維表的外鍵關聯。因為同一個表上可能有多個要參與關聯的外鍵字段,不可能讓同一個表同時針對多個字段都有序。這也是區分 JOIN 后采用了不同函數(算法)的原因。

總體來看,esProc 不僅能輕松實現跨庫關聯,還提供了不同關聯場景的實現算法,簡單區分后就能獲得明顯的編碼效率和運算效率的提升。

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

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

相關文章

Nacos源碼—4.Nacos集群高可用分析三

大綱 6.CAP原則與Raft協議 7.Nacos實現的Raft協議是如何寫入數據的 8.Nacos實現的Raft協議是如何選舉Leader節點的 9.Nacos實現的Raft協議是如何同步數據的 10.Nacos如何實現Raft協議的簡版總結 6.CAP原則與Raft協議 (1)CAP分別指的是什么 (2)什么是分區以及容錯 (3)為…

普通IT的股票交易成長史--20250509晚復盤

聲明: 本文章的內容只是自己學習的總結,不構成投資建議。價格行為理論學習可參考簡介中的幾位,感謝他們的無私奉獻。 送給自己的話: 倉位就是生命,絕對不能滿倉!!!!&…

python實現點餐系統

使用python實現點餐系統的增加菜品及價格,刪除菜品,查詢菜單,點菜以及會員折扣價等功能。 代碼: 下面展示一些 內聯代碼片。 # coding utf-8menu {拍黃瓜: 6, 小炒肉: 28, 西紅柿炒蛋: 18, 烤魚: 30, 紅燒肉: 38, 手撕雞: 45,…

從ellisys空口分析藍牙耳機回連手機失敗案例

問題背景: 前兩天同事發現我們現在做的項目,耳機在跟某些特定類型安卓手機(尤其是比較新的手機)回連會失敗,然后我幫他分析了一些log,記錄如下: 回連失敗所做步驟如下: 手機和耳機…

教育+AI:個性化學習能否顛覆傳統課堂?

近年來,人工智能(AI)技術迅猛發展,逐漸滲透到各行各業,教育領域也不例外。從智能輔導系統到自適應學習平臺,AI正在改變傳統的教學模式,使個性化學習成為可能。然而,這種變革能否真正…

【C++設計模式之Strategy策略模式】

C設計模式之Strategy策略模式 模式定義核心思想動機(Motivation)結構(Structure)實現步驟1. 定義策略接口(基于繼承)2.實現具體策略3.上下文類(Context)4. 在main中調用 應用場景(基于繼承)1.定義策略接口2.實現具體策略3.上下文類…

Python企業級MySQL數據庫開發實戰指南

簡介 Python與MySQL的完美結合是現代Web應用和數據分析系統的基石,能夠創建高效穩定的企業級數據庫解決方案。本文將從零開始,全面介紹如何使用Python連接MySQL數據庫,設計健壯的表結構,實現CRUD操作,并掌握連接池管理、事務處理、批量操作和防止SQL注入等企業級開發核心…

matlab轉python

1 matlab2python開源程序 https://blog.csdn.net/qq_43426078/article/details/123384265 2 網址 轉換網址:https://app.codeconvert.ai/code-converter?inputLangMatlab&outputLangPython 文件比較網址:https://www.diffchecker.com/text-comp…

Vue 3 中編譯時和運行時的概念區別

文章目錄 前言Vue 3 中的編譯時 vs 運行時區別模板在編譯時轉化為渲染函數編譯時的優化處理運行時的工作:創建組件實例與渲染流程前言 詳細整理 Vue 3 中編譯時和運行時的概念區別,并重點解釋為什么組件實例是在運行時創建的。 我會結合官方文檔、源碼分析和社區解釋,確保內…

Spring 框架實戰:如何實現高效的依賴注入,優化項目結構?

Spring 框架實戰:如何實現高效的依賴注入,優化項目結構? 在當今的 Java 開發領域,Spring 框架占據著舉足輕重的地位。而依賴注入作為 Spring 的核心概念之一,對于構建高效、靈活且易于維護的項目結構有著關鍵作用。本…

創建虛擬服務時實現持久連接。

在調度器中配置虛擬服務,實現持久性連接,解決會話保持問題。 -p 【timeout】 -p 300 這5分鐘之內調度器會把來自同一個客戶端的請求轉發到同一個后端服務器。【不管使用的調度算法是什么。】【稱為持久性連接。】 作用:將客戶端一段時間…

說下RabbitMQ的整體架構

RabbitMQ 是一個基于 AMQP(Advanced Message Queuing Protocol) 協議的開源消息中間件,RabbitMQ的整體架構圍繞消息的生產、路由、存儲和消費設計,旨在實現高效、可靠的消息傳遞,它由多個核心組件協同工作。 核心組件 …

STM32--GPIO

教程 視頻 博主教程 STM32系統結構圖 GPIO GPIO(General Purpose Input/Output)是STM32內部的一種外設。 一個STM32芯片內存在多個GPIO外設,每個GPIO外設有16個引腳; 比如GPIOA:PA0~PA15; GPIOB:PB0~…

QUIC協議優化:HTTP_3環境下的超高速異步抓取方案

摘要 隨著 QUIC 和 HTTP/3 的普及,基于 UDP 的連接復用與內置加密帶來了遠超 HTTP/2 的性能提升,可顯著降低連接握手與擁塞恢復的開銷。本文以爬取知乎熱榜數據為目標,提出一種基于 HTTPX aioquic 的異步抓取方案,并結合代理 IP設…

[論文閱讀]MCP Guardian: A Security-First Layer for Safeguarding MCP-Based AI System

MCP Guardian: A Security-First Layer for Safeguarding MCP-Based AI System http://arxiv.org/abs/2504.12757 推出了 MCP Guardian,這是一個框架,通過身份驗證、速率限制、日志記錄、跟蹤和 Web 應用程序防火墻 (WAF) 掃描來…

Redis客戶端緩存的4種實現方式

Redis作為當今最流行的內存數據庫和緩存系統,被廣泛應用于各類應用場景。然而,即使Redis本身性能卓越,在高并發場景下,應用與Redis服務器之間的網絡通信仍可能成為性能瓶頸。 這時,客戶端緩存技術便顯得尤為重要。 客…

eNSP中路由器OSPF協議配置完整實驗和命令解釋

本實驗使用三臺華為路由器(R1、R2和R3)相連,配置OSPF協議實現網絡互通。拓撲結構如下: 實驗IP規劃 R1: GE0/0/0: 192.168.12.1/24 (Area 0)Loopback0: 1.1.1.1/32 (Area 0) R2: GE0/0/0: 192.168.12.2/24 (Area 0)GE0/0/1: 192.…

內網滲透——紅日靶場三

目錄 一、前期準備 二、外網探測 1.使用nmap進行掃描 2.網站信息收集 3.漏洞復現(CVE-2021-23132) 4.disable_function繞過 5.反彈shell(也,并不是) 6.SSH登錄 7.權限提升(臟牛漏洞) 8.信息收集 9.上線msf 三…

解決Win11下MySQL服務無法開機自啟動問題

問題描述 在win11系統中,明明將MySQL服務設置成了自動啟動,但在重啟電腦后MySQL服務還是無法自動啟動,每次都要重新到計算機管理的服務中找到服務再手動啟動。 解決方式 首先確保mysql服務的啟動類型為自動。 設置方法:找到此電…

后端項目進度匯報

項目概述 本項目致力于構建一個先進的智能任務自動化平臺。其核心技術是一套由大型語言模型(LLM)驅動的后端系統。該系統能夠模擬一個多角色協作的團隊,通過一系列精心設計或動態生成的處理階段,來高效完成各種復雜任務&#xff…