如何從800萬數據中快速撈出自己想要的數據?

来源:https://www.cnblogs.com/xiezhr/archive/2023/05/10/17343536.html
-Advertisement-
Play Games

(如何從800萬數據中快速撈出自己想要的數據) 一、需求調研 正如題目所說,我們使用的是Oracle資料庫,數據量在800萬左右。我們要完成的事情就是在著800萬數據中,通過某些欄位進行模糊查詢,得到我們所需要的結果集。 這是表裡的數據,一共7328976 條數據,接近800萬 select cou ...


目錄

一、需求調研

正如題目所說,我們使用的是Oracle資料庫,數據量在800萬左右。我們要完成的事情就是在著800萬數據中,通過某些欄位進行模糊查詢,得到我們所需要的結果集。

這是表裡的數據,一共7328976 條數據,接近800萬

select count(1) from t_material_new;

在這裡插入圖片描述
這是我們想要的結果,根據耗材名稱生產企業名稱 或其他欄位模糊查詢出我們想要的結果集

select * from t_material_new t where (t.耗材名稱 like '%一次性%' ) and (t.生產企業名稱 like '%潔瑞醫用製品%');

在這裡插入圖片描述

二、常規思路

一聽到要模糊查詢,我們想到得關鍵字當然是like了。

like我們常用的有以下三種匹配方式

  • 欄位 like '%關鍵字%' 查詢出欄位包含”關鍵字”的記錄
  • 欄位 like '關鍵字%' 查詢出欄位以”關鍵字”開始的記錄
  • 欄位 like '%關鍵字' 查詢出欄位以”關鍵字”結束的記錄

我們都知道like關鍵字的查詢效率比較低,我們來看下具體查詢效率
1、欄位 like '%關鍵字%' 方式

-- 1、查詢包含關鍵字記錄 需要花費5.61s
select * from t_material_new t where (t.耗材名稱 like '%一次性%' ) and (t.生產企業名稱 like '%潔瑞醫用製品%');

在這裡插入圖片描述
2、欄位 like '關鍵字%' 方式

-- 2、查詢以”關鍵字”開始的記錄  花費0.203s
select * from t_material_new t where (t.耗材名稱 like '真空採血%') and (t.生產企業名稱 like '重慶三豐醫療器%');

在這裡插入圖片描述
3、 欄位 like '%關鍵字' 方式

3、查詢以”關鍵字”結束的記錄 花費0.484s
select * from t_material_new t where (t.耗材名稱 like '%腸內') and (t.生產企業名稱 like '%療器械有限公司');

在這裡插入圖片描述
通過以上測試,我們可以得出以下結論

  • 欄位 like '%關鍵字%' 沒法走索引,效率極低
  • 欄位 like '關鍵字%'欄位 like '%關鍵字' 可以走到索引,查詢效率可以接受

我們讓用戶通過第二種、或第三種方式檢索也不太現實。
那就只能想想辦法看能不能優化了。

四、尋找解決方案

遇到問題總是要解決的,然後就去請教大佬了。
在這裡插入圖片描述

在這裡插入圖片描述
咨詢後小結:
(1)建立函數索引

原來函數也是可以建立索引的,get到新技能了。但是這裡的由於函數入參內容的不確定性,沒法建立函數索引。這種方案便被否決了

(2)提升硬體質量

作為一名資深打工人,提升硬體質量當然不是由我能決定的了。

以上兩種方案都不行,那就只能另闢蹊徑了。
問了度娘之後,從網上有找到了兩種相對靠譜的方案。
在這裡插入圖片描述
1、將like 關鍵字替換為instr 函數
2、建立全文索引

四、說乾就乾,實現它

1 將like 改為instr函數

① 函數簡介

instr 俗稱字元查找函數。用於查找目標字元串在源字元串中出現的位置

② 語法格式

-- sourceString 代表源字元串
-- destString  代表目標字元串
-- start 代表從源字元串查找開始位置,預設為1,可以省略 負數表示倒數第幾位開始查找
-- appearPosition 代表想從源字元中查找出第幾次出現目標字元串destString 預設為1,可以省略
instr(sourceString,destString,start,appearPosition)
instr('源字元串', '目標字元串' ,'開始位置','第幾次出現')

③ 舉個慄子

-- 省略後兩個預設參數
select instr('helloworld','l') from dual; --返回結果:3 即第一次出現"l"的位置是第3位
select instr('helloworld','wo') from dual; --返回結果:6 即第一次出現"wo"的位置是第6位
select instr('helloworld','wr') from dual; --返回結果:0 即未查找到字元串"wr"
--帶上後兩位參數
select instr('helloworld','l',2,2) from dual;  --返回結果:4 即在"helloworld"的第2位(e)開始,查找第二次出現的"l"的位置是4
select instr('helloworld','l',-2,3) from dual; --返回結果:3 即在"helloworld"的倒數第2(l)號位置開始,往回查找第三次出現的“l”的位置是3

④ 用instr函數改寫上面的sql

select * from t_material_new t where (t.耗材名稱 like '%一次性%' ) and (t.生產企業名稱 like '%潔瑞醫用製品%');  -- 得到結果集需要 6.11秒
-- 相當於
select * from t_material_new t where instr(t.耗材名稱,'一次性')>0 and instr(t.生產企業名稱, '潔瑞醫用製品')>0;  -- 得到結果集只需要3.812秒

小結:用instr函數改寫like 關鍵字後,查詢效率明顯提高了。
但是,還有沒有其他方式可以再優化一下呢?
經過小編堅持不懈的問度娘之後,還真找到了另一個方法,那就建立全文索引。
建立全文索引有點複雜,具體操作參照【2使用Oracle全文索引】

2 使用Oracle全文索引

溫馨提示:建立索引是需要占用一部分磁碟空間的,這其實也是我們常說的以空間換取時間

① Oracle版本的要求

Oracle 10g或以上版本才支持,其他低版本的就不能使用了

② 建立索引前準備工作

oracle全文檢索需要ctxsys用戶的支持,我們需要使用ctxsys用戶下的ctx_ddl這個包。
在建立全文索引過程中,基本上都在使用這個包。

我們在安裝Oracle的時候,ctxsys用戶可能沒啟用。
我們這裡要做的有兩步
Ⅰ 解鎖ctxsys用戶,以獲得ctx_ddl包的使用許可權。

-- 需要以Oracle管理員system用戶進行解鎖
alter user ctxsys account unlock; 

Ⅱ 將ctx_ddl包的操作許可權賦給需要操作的用戶

grant execute on ctx_ddl to testuser;  

③創建分析器

oracle text的分析器 ,類似於lucene中的分詞器,將需要檢索的記錄,按照一定的方式進行片語拆分,然後存放在索引表中。檢索的時候根據索引表中存放的拆分片語,對傳入的關鍵字進行匹配,並返回匹配結果集。

oracle text中的分析器有3種:

  • basic_lexer:只能根據空格和標點來進行拆分。比如“雲南楚雄”,只能拆分為“雲南楚雄”一個片語
  • chinese_vgram_lexer:專門的漢語分析器,按字單元進行拆分,比如“雲南楚雄”,可以拆分為“雲”、“雲南“、”南楚”、“楚雄”、“雄”五個片語。這種方式的好處是能夠將所有有可能的片語全部保存進索引表,使得數據不會遺漏。
  • chinese_lexer:一種新的漢語分析器,能夠認識大部分常用的漢語辭彙,並按常用辭彙進行拆分存儲。比如“雲南楚雄”,只會被拆分為“雲南”、“楚雄”兩個片語。

為了是的需要檢索的數據不會出現遺漏,這裡我們選擇chinese_vgram_lexer 這個分詞器

登錄我們需要查詢數據的用戶,以chinese_vgram_lexer 這種分詞器方式創建分析器

-- 創建一個“chinese_vgram_lexer”分析器,名稱為my_lexer
begin
ctx_ddl.create_preference ('my_lexer', 'chinese_vgram_lexer');  
end;

④ 創建過濾片語
我們在檢索數據的時候,通常不需要某些片語進行檢索,就如同上面查詢條件中的生產企業
我們不希望輸入“公司”“有限公司”“有限責任公司”等這樣的關鍵詞,也會檢索出結果。

我們就可以通過建立過濾片語,以實現創建索引的時候將這些片語過濾掉

-- 創建一個片語過濾器
begin
ctx_ddl.create_stoplist('my_stoplist');  
end;
-- 往片語過濾器中添加過濾關鍵字
begin
ctx_ddl.add_stopword('my_stoplist','公司');  
ctx_ddl.add_stopword('my_stoplist','股份有限公司');  
ctx_ddl.add_stopword('my_stoplist','有限責任公司');  
end;

⑤ 到了最重要的一步,建立索引
以上所有都是為這一步準備的。

根據需求,我們需要對錶t_material_new 中的耗材名稱生產企業名稱進行檢索。
所以我們需要以耗材名稱生產企業名稱欄位建立索引。建立腳本如下

註:以下腳本在執行的時候需要花費一點時間,耐心等待即可

-- 在t_material_new表中的【耗材名稱】和【生產企業名稱】欄位上創建索引,索引類系那個為context類型,該索引用到的分析器為前面定義的my_lexer,該索引用到的過濾片語為前面定義得my_stoplist
create index INDEX_MATERIAL_NAME on t_material_new(耗材名稱) indextype is CTXSYS.CONTEXT parameters('lexer my_lexer stoplist my_stoplist'); 

create index INDEX_MATERIAL_PROD on t_material_new(生產企業名稱) indextype is CTXSYS.CONTEXT parameters('lexer my_lexer stoplist my_stoplist'); 

創建完索引後,我們會發現當前用戶下,關於INDEX_MATERIAL_NAME 索引多了四個表,關於
INDEX_MATERIAL_PROD 也多了四個表。

在這裡插入圖片描述在這裡插入圖片描述
其中t_material_new表中【耗材名稱】欄位被拆分後的片語保存在dr\(index_material_name\)i表中
其中t_material_new表中【生產企業名稱】欄位被拆分後的片語保存在dr\(index_material_prod\)i表中

我們來查詢下表的具體內容看看

select * from dr$index_material_name$i;

在這裡插入圖片描述

select * from dr$index_material_prod$i;

在這裡插入圖片描述
⑥ 如何使用索引?

-- 將以上查詢sql改下為用全文索引的查詢方式 (查詢出我們想要的結果集僅僅需要0.312秒)
select * from t_material_new t where contains(t.耗材名稱,'一次性')>0 and contains(t.生產企業名稱, '潔瑞醫用製品')>0; 

到此,基本上已經圓滿完成了我們的需求任務。
我們做到了模糊查詢從 6.11秒--> 3.812秒--> 0.312秒

可能細心的小伙伴會發現一個問題,
如果表t_material_new 中插入了新的數據,那麼分析器中不就沒記錄到這些詞了嗎?

小伙伴提的這個問題挺好的,當然我們也有對應的方法解決

⑦ 完善我們的索引

當我們需要修改t_material_new 表中的數據,比如添加、刪除、更新等操作時,INDEX_MATERIAL_NAME和INDEX_MATERIAL_PROD索引是不會同步更新數據的,需要我們在程式中手動的更新。

-- 更新同步索引中分詞數據
begin
ctx_ddl.sync_index('INDEX_MATERIAL_NAME')  
ctx_ddl.sync_index('INDEX_MATERIAL_PROD')  
end 

當然了我們可以在表t_material_new 上寫一個oracle的觸發器,當添加、刪除、修改操作時,進行索引分詞更新;或者創建定時任務定時更新也可以。

定時任務的建立可以參照之前寫過的文章
Oralce定時任務實際應用

到此,Oracle模糊查詢優化就算完成了,但是還想分享一個小技巧。
怎麼將excel 表格中的數據快速導入到Oracle資料庫中呢?
要是數據少,都好說。當數據量到幾十萬、或者幾百萬的時候就比較難了。
這裡推薦用Navicat工具導入
在這裡插入圖片描述
在這裡插入圖片描述

個人親自實測,導入速度還是挺快的。

以上就是文章的全部內容了,希望對你有所幫助


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

-Advertisement-
Play Games
更多相關文章
  • Scala 只是學習無基本理論 安裝Scala 裝前必須有jdk windows安裝 解壓縮 D:dev/scala 配置環境變數 SCALA_HONE path cmd檢查 Scala -version 直接輸入Scala 控制台運行 idea安裝與運行Scala idea-->插件-->scal ...
  • 目錄 一、引導分區 二、服務控制 三、運行級別 四、systemd初始化 五、模擬錯誤 一、引導分區 原理:引導分區是指在開機啟動到進入系統這之間的過程 引導分區的過程:1.開機自檢 自檢順序:BIOS,cup,記憶體,顯卡,鍵盤 根據預設的順序控制權交給硬碟(第一個硬碟或者光碟機) 2.mbr引導 機 ...
  • 收藏!最全Linux思維導圖 1. 認識 Linux 2. Linux 命令 3. Linux學習路徑 4. Linux 桌面介紹 5. FHS:文件系統目錄標準 6. Linux 需要特別註意的目錄 7. Linux 內核學習路線 8. Linux Security Coaching 9. Lin ...
  • macOS系統中預設的C/C++編譯器是clang/clang++,命令行使用gcc/g++或者clang/clang++來執行命令時,都是調用clang/clang++編譯器,想使用gcc/g++編譯器的話,我們可以自己安裝。 查看一下gcc和clang 1. 安裝Homebrew,官網鏈接,複製 ...
  • 在一個Oracle 12.1實例中,想監控一個表的索引使用情況,在system用戶下執行了下麵腳本以及輸出的監控索引腳本後,發現V$OBJECT_USAGE下一直沒有對應的記錄(在system用戶下查詢) SELECT 'ALTER INDEX '||OWNER||'.'||INDEX_NAME|| ...
  • (Oracle之table()函數) 一、序言 前段時間一直在弄報表,快被這些報表整吐了,然後接觸到了Oracle的table()函數。所以今天把table()函數的具體用法整理下,防止下次遇到忘記了。。 利用table()函數,可接收輸入參數,然後將pl/sql 返回的結果集代替table。由於表 ...
  • 摘要:在技術領域中,沒有銀彈。我們需要不斷探索和研究新的技術,結合具體問題和需求,選擇最適合的解決方案。 本文分享自華為雲社區《知乎問題:如何說服技術老大用 Redis ?》,作者:勇哥java實戰分享。 最近在某問答平臺看到一個技術討論:如何說服技術老大用Redis? “他總覺得用Redis每次都 ...
  • 摘要:本文以華為雲圖引擎 GES 為例,來介紹如何使用圖查詢語言 Cypher 表達一些需要做數據局部遍歷的場景。 本文分享自華為雲社區《使用 Cypher 子查詢進行圖探索 -- 以華為雲圖引擎 GES 為例》,作者:蜉蝣與海。 在圖資料庫 / 圖計算領域,很多查詢可以使用圖查詢語言 Cypher ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...