not in/ not exists 有哪些可以替代操作

来源:https://www.cnblogs.com/lottu/archive/2019/09/24/11578835.html
-Advertisement-
Play Games

需求 例如一張A表(id, userid, info);其中id為自增長主鍵。存在userid重覆記錄;並一直有新數據增加,現需要根據userid去重並實時插入表B。 用SQL語法來解釋: 其中需要改寫的語句是 -- 在表B插入百萬條記錄insert into B select level, dbm ...


需求
  例如一張A表(id, userid, info);其中id為自增長主鍵。存在userid重覆記錄;並一直有新數據增加,現需要根據userid去重並實時插入表B。

用SQL語法來解釋:

-- 獲取表B中記錄最大id
select max(id) from B 

-- 根據上面獲取的id;提取最新的A表記錄;根據userid去重;並插入中間表TMP_B;
INSERT INTO TMP_B
  SELECT id, userid, info
    FROM (select id,
                 userid,
                 info,
                 ROW_NUMBER() OVER(PARTITION BY userid ORDER BY id) RN
            FROM A
           WHERE id > ?)
   WHERE RN = 1;

-- 把上面獲取的記錄;不存在則插入表B
insert into B
  select id, userid, info
    from TMP_B
   where userid not in (select userid from B);
            
-- 或者用not exists
insert into B
  select id, userid, info
    from TMP_B tb
   where not exists (select 1 from B b where b.userid = tb.userid);

其中需要改寫的語句是

select id, userid, info
    from TMP_B
   where userid not in (select userid from B);  
-- 插入實驗數據

-- 在表B插入百萬條記錄
insert into B select level, dbms_random.string('x',8), 'lottu'||level from dual connect by level <= 1000000;
-- 在表TMP_B插入十萬條記錄
insert into TMP_B select level, dbms_random.string('x',8), 'lottu'||level from dual connect by level <= 100000;

通過執行計劃;會發現not in/ not exists 效率相差不大。

insert into B
select id, userid, info  from TMP_B tb
where not exists (select 1 from B b where b.userid = tb.userid);

100000 rows created.

Elapsed: 00:00:00.52
Execution Plan
----------------------------------------------------------
Plan hash value: 3462170537
------------------------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes |TempSpc| Cost (%CPU)|Time     |
------------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT     |     |   115K|  4389K|     |  2994   (1)|00:00:36 |
|   1 |  LOAD TABLE CONVENTIONAL | B     |     |     |     |          |     |
|*  2 |   HASH JOIN ANTI     |     |   115K|  4389K|  4960K|  2994   (1)|00:00:36 |
|   3 |    TABLE ACCESS FULL     | TMP_B |   115K|  3601K|     |   137   (1)|00:00:02 |
|   4 |    TABLE ACCESS FULL     | B     |  1375K|  9403K|     |  1372   (1)|00:00:17 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("B"."USERID"="TB"."USERID")
Note
-----
   - dynamic sampling used for this statement (level=2)

Statistics
----------------------------------------------------------
      0  recursive calls
       3221  db block gets
       6320  consistent gets
     35  physical reads
    3649980  redo size
    845  bytes sent via SQL*Net to client
    866  bytes received via SQL*Net from client
      3  SQL*Net roundtrips to/from client
      1  sorts (memory)
      0  sorts (disk)
     100000  rows processed

替換1: 通過merge into改寫語句

merge into B b
using TMP_B tb
on (tb.userid = b.userid)
WHEN NOT MATCHED THEN
  INSERT (b.id, b.userid, b.info) values (tb.id, tb.userid, tb.info);

通過執行計劃;該SQL會占用記憶體用於排序。效率會有大大的提升。 特別是在B數據量很大的情況。優勢更明顯。

Elapsed: 00:00:00.18

Execution Plan
----------------------------------------------------------
Plan hash value: 2722554344
--------------------------------------------------------------------------------------

| Id  | Operation         | Name  | Rows  | Bytes |TempSpc| Cost (%CPU)| Time|
--------------------------------------------------------------------------------------
|   0 | MERGE STATEMENT      |         |     115K|    7203K|         |    5298   (1)| 00:01:04 |
|   1 |  MERGE             | B     |         |         |         |          ||
|   2 |   VIEW             |         |         |         |         |          ||
|*  3 |    HASH JOIN OUTER   |         |     115K|    8553K|    4960K|    5298   (1)| 00:01:04 |
|   4 |     TABLE ACCESS FULL| TMP_B |     115K|    3601K|         |     137   (1)| 00:00:02 |
|   5 |     TABLE ACCESS FULL| B     |    1336K|      56M|         |    1373   (1)| 00:00:17 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("TB"."USERID"="B"."USERID"(+))
Note
-----
   - dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
      0  recursive calls
      0  db block gets
       5496  consistent gets
      0  physical reads
      0  redo size
    844  bytes sent via SQL*Net to client
    896  bytes received via SQL*Net from client
      3  SQL*Net roundtrips to/from client
      1  sorts (memory)
      0  sorts (disk)
      0  rows processed

替換2: 通過kettle工具,設置轉換;通過shell命令;用cron或者其他調度系統調用。該操作相對用戶是透明的;至於效率方面有待驗證。

 

 看到此處的朋友,若有更好的方法;歡迎在下評論;一起討論。

最後該需求若在PostgreSQL中;有更簡潔的的寫法.簡單粗暴。

INSERT INTO B
 SELECT *
FROM A on conflict (userid) do nothing;

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  •     查看內部命令和外部命令幫助 一、內部命令   可以用type來判斷該命令是內部命令還是外部命令,type後加要查看的命令. 示例寫法:type enable   有的命令既有內部命令也有外部命令但是系統會優先使用 ...
  • 網路上已經有許多在kernel中修改開機Logo的文章,本文就LK下實現開機logo進行簡述 需要用到ffmpeg工具,沒有安裝ffmpeg請參考這裡: "http://blog.csdn.net/redstarofsleep/article/details/45092145" 運行"ffmpeg ...
  • [TOC] 第十六章、資料庫之多表關係 欄位操作 多表關係 外鍵 一對一:無級聯關係 一對一:有級聯關係(外鍵加unique約束) 一對多 多對多 ...
  • 一直以為很瞭解sqlserver的加鎖過程,在分析一些特殊情況下的死鎖之後,尤其是併發單表操作發生的死鎖,對於加解鎖的過程,有了一些重新的認識,之前的知識還是有一些盲區在裡面的。delete加鎖與解鎖步驟是怎麼樣的?什麼時候對那些對象,加什麼類型的瑣,加鎖與索引的關係是怎麼樣的,什麼時候釋放鎖?整個 ...
  • 分片,唯一索引和upsert,錶面上看似沒有直接聯繫的幾個東西,到底存在怎樣的瓜葛呢? ...
  • 三層架構 嚴格分層架構模式的特點是上層只能訪問相鄰的下層,其他層次間的調用都不允許。三層架構就是一種嚴格分層模式,它把職責劃分為界面展示、業務邏輯、數據訪問三層,還有一個業務實體,前面三層都要依賴它,所以它並不構成一個層。 三層架構的特點是一種面向過程的編程思想,特點如下: a. 業務實體類中基本上 ...
  • 概述 NodeManager是運行在單個節點上的代理,它需要與應用程式的的ApplicationMaster和集群管理者ResourceManager交互: 從ApplicationMaster上接收有關Container的命令並執行之(比如啟動,停止Container); 向ResourceMan ...
  • Apache 是一個高可用、高可靠的,分散式的海量日誌採集、聚合、傳輸系統,基於流式架構,靈活簡單。 Flume 最主要的作用就是實時讀取伺服器本地磁碟的數據,將數據寫入HDFS中。 Flume組成架構詳解: Source輸入端常用的類型有:spooling directory、exec、avro、 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...