SQLServer中間接實現函數索引或者Hash索引

来源:http://www.cnblogs.com/wy123/archive/2017/03/26/6617700.html
-Advertisement-
Play Games

本文出處:http://www.cnblogs.com/wy123/p/6617700.html SQLServer中沒有函數索引,在某些場景下查詢的時候要根據欄位的某一部分做查詢或者經過某種計算之後做查詢,如果使用函數或者其他方式作用在欄位上之後,就會限制到索引的使用,不過我們可以間接地實現類似於 ...


 

本文出處:http://www.cnblogs.com/wy123/p/6617700.html 

 

SQLServer中沒有函數索引,在某些場景下查詢的時候要根據欄位的某一部分做查詢或者經過某種計算之後做查詢,
如果使用函數或者其他方式作用在欄位上之後,就會限制到索引的使用,不過我們可以間接地實現類似於函數索引的功能。
另外一個就是如果查詢欄位較大或者欄位較多的時候,所建立的索引就顯得有點笨重,效率也不高,
就需要考慮使用一個較小的"替代性"欄位做等價替換,類似於Hash索引,
本文粗淺地介紹兩種上述兩種問題的解決方式,僅供參考。

 

1,在計算列上建索引,實現“函數索引”的功能

  SQLServer在建表的時候允許使用計算列,可以藉助這個計算列來實現函數索引的功能,這裡舉例說明一下

Create Table TestFunctionIndex
(
    id int identity(1,1),
    val varchar(50),
    subval as LOWER(SUBSTRING(val,10,4)) persisted --增加一個持久化計算列
)
GO

--在持久化計算列上建立索引
create index idx_subvar on TestFunctionIndex(subval)
GO

--插入10W行測試數據
insert into TestFunctionIndex(val) values (NEWID())
go 100000

在有索引的欄位上使用函數之後,是無法使用索引的

  如果直接在計算列上查詢,就可以正常地使用到索引了

  

  以上通過在計算列上建立一個索引,可以根據計算列上的索引做查找,避免了直接在欄位上使用函數或者其他操作,造成即便欄位上有索引也用不到的情況

  補充:
  測試中神奇地發現,如果計算列欄位上建立了索引,在原始欄位上使用函數與計算列的函數一樣的時候,可以神奇地使用到計算列上的索引
  可見SQLServer在我們沒有註意的地方也是下了不少功夫的啊

  

 

 

2,生成較長欄位或者多個欄位的Hash值替代原始欄位做查詢或者連接來提升查詢效率

  開發中遇到另外一種常見的情況是經常使用到的查詢條件欄位較長,或者是表連接的時候連接條件欄位較多,
  即便是欄位或者查詢條件上有索引,但是因為欄位較長或者條件較多,此時有可能會影響到查詢的效率
  這種情況就適當考慮將原始的較長的欄位生成一個較小的欄位(但是要確保唯一性),或者是講多個欄位生成一個較短的數據類型做替代,以提高查詢的效率

  舉個例子,假如有這麼一張表,Name欄位是我模擬出來的,Name是一個比較長的欄位,又要用來做檢索
  意思就是查詢欄位較長,索引代價太大,此時就需要考慮用一種較小的等價欄位來替代
  下麵通過某種方式計算較長欄位的Hash值,來做等價替換

  

  模擬生成一下測試數據

Create table testHashColumn
(
    id int identity(1,1),
    QueryName nvarchar(100),
    HashName AS CAST( HASHBYTES('MD2',QueryName)  AS UNIQUEIDENTIFIER) persisted
)
GO

create index idx_HashName ON testHashColumn(HashName)
GO

--這裡模擬生成一個較長的名字欄位
DECLARE @i int = 0
while @i<10000
begin 
    INSERT INTO testHashColumn (QueryName) VALUES (CONCAT('北京新視點科技文化傳媒有限公司',@i))
    set @i = @i+1
end

我們知道,Name這個名字是nvarchar(100)的,這個欄位做索引不是不可以,
如果情況複雜,實際中有可能比這個欄位更大,做索引顯得太寬了,造成索引空間過大,在效率上有一定程度的影響。

這裡就可以考慮在Name這個欄位上生成一個“替代”欄位(上述HashName AS CAST( HASHBYTES('MD2',QueryName) AS UNIQUEIDENTIFIER) persisted這個計算列),

這個欄位首選是要跟實際值一一對應的,另外就是要求“替代”的欄位類型要求相對較小,
當然方法也有多種,比如生成利用checksum函數生成一個校驗值,
但是據實際觀察checksum生成的校驗值是有可能重覆的,也就是說兩個不同的字元串,生成同一個校驗值
比如這樣,很容易驗證出來這個問題,可以認為是對於不同的字元串,計算之後得到同一個校驗和

  因此在生成“替代”欄位的時候,需要考慮計算值的唯一性
  這裡使用的是HASHBYTES加密函數,對字元串加密,然後對加密之後的數據生成一個UNIQUEIDENTIFIER,重覆的概率就小的多的多了
  演示這裡通過CAST( HASHBYTES('MD2','北京新視點科技文化傳媒有限公司999') AS UNIQUEIDENTIFIER)的方式,就可以給這個較長的欄位生成一個UNIQUEIDENTIFIER類型的欄位,
  當然也不一定只有這一種方法,甚至可以做的跟複雜,只要能保證一個唯一的長欄位生成的較短的欄位也是唯一的就可以達到目的了
  參考如下查詢,就可以使用HashName計算出來的值與計算列做比較,在一定程度上可以減少檢索欄位索引的大小,又能達到目的的效果

   如截圖,就可以使用HashName欄位上的索引了,同時也避免了在原始的QueryName這個較長的欄位上建索引,節約了空間並提高了查詢效率

 

3, 邏輯主鍵為多個欄位的時候,在多了欄位上生成一個“替代”性的唯一欄位

  某些情況下業務需求或者設計也好(比如沒有達到第三範式,BC範式,第四範式,甚至是第五範式),在表連接的時候往往會有多個欄位
  比如這種樣子:

SELECT *
FROM TableNameA a
INNER JOIN TableNameB b
    ON a.key=b.key
        AND a.Type = b.Type
        AND a.Status = b.Staus
        AND a.CreationTime = b.CreationTime
        AND a.***=b.***
where ***

    在表關聯的時候,連接條件很多,
  如果是這樣子,最好的情況就是建立一個較寬的複合索引,
  但是這樣的話,索引的寬度和體積就變得很大,使用的時候效率也有一定的影響
  這種情況就可以考慮在TableNameA 和 TableNameB 上,
  利用多個連接的欄位(Key+Type +Status +CreationTime+***)做了類似於示例2中的一個計算列,在計算列上建立一個索引
  然後再表連接的時候就可以用如下的方式替代

SELECT *
FROM TableNameA a
INNER JOIN TableNameB b
    ON a.HashValue=b.HashValue
WHERE ***

  總是,這是一種以空間換時間的思路(冗餘存儲一個類似於標識符的欄位,提高查詢效率),
  在生成“替代”欄位的思想有兩點,第一要足夠的小,第二要原始值生成替代欄位的唯一性

 


總結:SQLServer 中沒有函數索引和Hash索引,而某些業務需求或者說是為了性能考慮,又需要類似的功能,
   通過類似於空間換時間的方法來實現,可以變通地來實現類似於函數索引或者Hash索引的功能,已達到其他資料庫中函數索引和Hash索引的效果(雖然原理可能不一樣)。
   需要註意的就是在生成計算列或者說Hash值替代的時候要註意計算方式,確保生成之後的Key值的唯一性
   當然實現方式就可以根據需要自行選擇了,條條大路通羅馬。

  

 


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

-Advertisement-
Play Games
更多相關文章
  • 有一個Button 按鈕,要想為該按鈕設置onClick事件和OnTouch事件 此時,我們現在分析一下,是onTouch先執行,還是onClick執行,接下來我從FrameWork 源碼去探尋一下整個事件的執行流程和原理: 我們知道 Button ,TextView 等基礎控制項的基類都是View, ...
  • 主要原理:是在主界面有兩個空間,一個是EditText,一個是ListView,ListView是放在EditText下麵的,然後自定義建立一個adapter適配器, 這個適配器要繼承Filterable這個介面,並實現這個介面的兩個方法,一個是過濾方法,一個是過濾後的方法,一般我們是在過濾方法裡面 ...
  • Android原生的CalendarView根本無法滿足我們日常開發的需要,在開發吾記APP的過程中,我覺得需要來一款高性能且美觀簡潔的日曆控制項,覺得魅族的日曆風格十分適合,於是打算擼一款。 github地址:https://github.com/huanghaibin-dev/CalendarVi ...
  • 想獲取用戶各項行為數據嗎? 想輕鬆查看用戶行為圖表嗎? 想高效進行 App 運營管理嗎? 想,來我帶你玩轉 App 數據統計。這裡我使用專業、輕便的 "JAnalytics" 。 本文內容分為兩部分:代碼示例&使用技巧部分、控制台圖表查看部分。 代碼示例&使用技巧 集成 1. 下載 "JAnalyt ...
  • 本文並非最終版本,如果想要關註更新或更正的內容請關註文集,聯繫方式詳見文末,如有疏忽和遺漏,歡迎指正。 本文相關目錄: ================== 所屬文集: "【iOS】07 設備工具 " ================== "7.4 定位服務 1.0 簡介" "7.4 定位服務 2. ...
  • Context,中文直譯為“上下文”,SDK中對其說明如下: 1、它描述的是一個應用程式環境的信息,即上下文。 2、該類是一個抽象(abstract class)類,Android提供了該抽象類的具體實現類。 3、通過它我們可以獲取應用程式的資源和類,也包括一些應用級別操作,例如:啟動一個Activ ...
  • 轉載請註明出處:http://www.cnblogs.com/cnwutianhao/p/6611252.html 引言:項目開發有時會使用上傳文件到伺服器,再從伺服器取數據顯示到本地這一過程;或者輸入一段文字,再把文字顯示出來。這個過程都用到了IO流。 IO流分為字元流(Reader\Writer ...
  • 最近公司開發一個項目,要求app能夠發送簡訊並獲取送達報告。這本不是一個什麼難題,實現這一功能的代碼一搜一大把,那麼這麼簡單的一個問題,為什麼我要在這裡提出來呢?那是因為我在寫代碼的時候掉入了一個坑,而且這很可能發生在很多和我一樣粗心的朋友身上。先給大家分享一下當初讓我掉進坑裡的代碼: 咋一看,好像 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...