都說Dapper性能好,突然就遇到個坑,還是個性能問題

来源:https://www.cnblogs.com/s0611163/archive/2022/08/12/16578447.html
-Advertisement-
Play Games

本來閑來無事,準備看看Dapper擴展的源碼學習學習其中的編程思想,同時整理一下自己代碼的單元測試,為以後的進一步改進打下基礎。 突然就發現問題了,源碼也不看了,開始改代碼,改了好久。 測試Dapper.LiteSql數據批量插入的時候,耗時20秒,感覺不正常,於是我測試了非Dapper版的Lite ...


本來閑來無事,準備看看Dapper擴展的源碼學習學習其中的編程思想,同時整理一下自己代碼的單元測試,為以後的進一步改進打下基礎。
突然就發現問題了,源碼也不看了,開始改代碼,改了好久。

測試Dapper.LiteSql數據批量插入的時候,耗時20秒,感覺不正常,於是我測試了非Dapper版的LiteSql的批量插入,僅需100毫秒,速度差了200倍。
同樣的資料庫、同樣的Npgsql.dll、同樣的測試代碼,產生的SQL和參數集合也是一樣的,最後不得不懷疑Dapper。
引用Dapper的源碼,修改調試之後,我決定提個PR。我之前沒想過提PR,我想我也不是為了提PR而提PR,我也不想費時費力。

沒想到提PR的過程很不順利,原來提的PR需要單元測試全部通過才行。
我本機沒環境不方便測,不過我發現提交申請之後,GitHub上立馬自動編譯測試,能看到哪些單元測試對了,哪些錯了,真強大,真方便,原來大工程是這樣的。

先是提交了一行代碼,認為沒有問題,結果被打了個叉。仔細一看才發現,原來是單元測試不通過。
改了又改,有幾個存儲過程相關的單元測試總是不通過。
都快要放棄了,後來想到是不是我定義的cleanNames變數隨著DynamicParameters類的創建,又清空了,但cleanNames又不能定義成全局的。後來我加了幾行代碼。
一共提交了12次,單元測試終於全部通過,共增加了11行代碼。
PR是提交了,是否被採納就不知道了。也許代碼寫的比較挫,也許審核人員不認可我對Dapper的這種用法,是我用錯了,沒有修改的必要。

修改DynamicParameters.cs文件

變數定義:

private readonly HashSet<string> cleanNames = new HashSet<string>();

單元測試始終無法全部通過,我添加了下麵幾行代碼,終於成功了。原來cleanNames被重新new了之後,command.Parameters里可能是有值的,它的作用域更大一些。

foreach (IDbDataParameter param in command.Parameters)
{
    if (!cleanNames.Contains(param.ParameterName))
    {
        cleanNames.Add(param.ParameterName);
    }
}

關鍵的修改就一行
原代碼(參數很多時性能不行,參數什麼情況下會很多呢?就是通過一條SQL批量Insert時會有很多參數,我是500條數據插入一批,參數根據表欄位多少可能有幾千個):

bool add = !command.Parameters.Contains(name);

當command.Parameters中有幾千個參數的時候,性能就慘不忍睹了。
集合查找的時間複雜度是O(N)。(原來我寫的是O(N/2),現更正為O(N))

修改為(HashSet性能很高):

bool add = !cleanNames.Contains(name);

通過HashSet查找,時間複雜度是O(1)。

往cleanNames中添加欄位名:

if (add)
{
    command.Parameters.Add(p);
    cleanNames.Add(name);
}

總結

  1. 關於List集合的Contains方法

    當你使用Contains方法的時候,你要考慮這個集合有沒有可能突然變的數據量很大?如果是在迴圈中頻繁調用,並且List的數據量比較大,它的性能就比較差,建議使用HashSet或Dictionary來判查找。
    但是HashSet、Dictionary和List轉來轉去也有代價,IDbCommand介面的Parameters屬性的類型是IDataParameterCollection,它是一個集合,並沒有HashSet或Dictionary類型的屬性,又必須要轉換才能得到。

提的issue和PR

issue:https://github.com/DapperLib/Dapper/issues/1817
PR:https://github.com/DapperLib/Dapper/pull/1816

LiteSql源碼

LiteSql源於DBHelper,裡面的介面是做過實際項目的,主要是ERP、CRM系統。
簡單支持了Lambda表達式、增加了SqlString之後,使用上似乎變複雜了一點,不過原來的使用方式依然支持。
也許這裡面的介面和設計思想,體現的是我上家公司的前輩們的技術水準。比如實體類用partial修飾分成兩個文件,可能有利有弊吧。自動生成的Model類是不建議修改的,否則資料庫變動的時候你還怎麼自動生成?不把你的改動衝掉了?
一個ORM有它的設計思想和理念,比如DapperExtensions就不建議對實體類加特性,而是通過獨立的映射類來處理表、欄位別名,優缺點我還不清楚。
LiteSql的後續改進,還沒有新的指導思想,所以一直都是小改,基本沒怎麼動。

https://gitee.com/s0611163/Dapper.LiteSql

https://gitee.com/s0611163/LiteSql
即使是大名鼎鼎的Dapper我依然不放心,所以保留了ADO.NET的版本。

最後

性能測試,我測試了MySQL和PostgreSQL的批量插入,奇怪的是,MySQL是沒有該性能問題的,PostgreSQL有性能問題,可是跑的是一樣的源碼,我想問題出在command.Parameters.Contains,MySql.Data.dll(版本6.9.12)中做了優化沒有問題,Npgsql.dll(4.0.13版本、4.1.12版本(大版本4的最後一個小版本)和5.0.14版本(大版本5的最後一個小版本))中沒有做優化存在性能問題,不過Npgsql.dll(6.0.6版本(最新版本))是做了優化的沒有性能問題。

這不是Dapper的問題,是Npgsql.dll 5.0.14 以及之前版本的問題,最後,我關閉了提了issue和PR。

最後發現不是Dapper的問題,也是尷尬。我之前也給NLog提過issue,測到最後發現NLog是真的沒有問題,是我自己配置的問題,尷尬。這都能水一篇博客,是我大意了,大家輕噴。

不過以後遇到這種情況,我怎麼知道我調用的Contains方法有沒有經過優化呢?每個都測一遍?


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

-Advertisement-
Play Games
更多相關文章
  • 我國目前並未出台專門針對網路爬蟲技術的法律規範,但在司法實踐中,相關判決已屢見不鮮,K 哥特設了“K哥爬蟲普法”專欄,本欄目通過對真實案例的分析,旨在提高廣大爬蟲工程師的法律意識,知曉如何合法合規利用爬蟲技術,警鐘長鳴,做一個守法、護法、有原則的技術人員。 案情介紹 深圳市快鴿互聯網科技有限公司 2 ...
  • 一、應用場景 大家在使用Mybatis進行開發的時候,經常會遇到一種情況:按照月份month將數據放在不同的表裡面,查詢數據的時候需要跟不同的月份month去查詢不同的表。 但是我們都知道,Mybatis是ORM持久層框架,即:實體關係映射,實體Object與資料庫表之間是存在一一對應的映射關係。比 ...
  • 背景 在 CI/CD 流程當中,測試是 CI 中很重要的部分。跟開發人員關係最大的就是單元測試,單元測試編寫完成之後,我們可以使用 IDE 或者 dot cover 等工具獲得單元測試對於業務代碼的覆蓋率。不過我們需要一個獨立的 CLI 工具,這樣我們才能夠在 Jenkins 的 CI 流程集成。 ...
  • 一:背景 上一篇我們聊到瞭如何去找 熱點函數,這一篇我們來看下當你的程式出現了 非托管記憶體泄漏 時如何去尋找可疑的代碼源頭,其實思路很簡單,就是在 HeapAlloc 或者 VirtualAlloc 時做 Hook 攔截,記錄它的調用棧以及分配的記憶體量, PerfView 會將這個 分配量 做成一個 ...
  • .NET 項目預設情況下 日誌是使用的 ILogger 介面,預設提供一下四種日誌記錄程式: 控制台 調試 EventSource EventLog 這四種記錄程式都是預設包含在 .NET 運行時庫中。關於這四種記錄程式的詳細介紹可以直接查看微軟的官方文檔 https://docs.microsof ...
  • 航天和軍工領域的數字化轉型和建設正在積極推進,在與航天二院、航天三院、航天六院、航天九院、無線電廠、兵工廠等單位交流的過程中,用戶更聚焦試驗和生產過程中的痛點,迫切需要解決軟體平臺統一監測和控制設備及軟體與設備協同的問題。 ...
  • 前兩天微軟偷偷更新了Visual Studio 2022 正式版版本 17.3 發佈,發佈摘要: MAUI 工作負荷 GA 生成 MAUI/Blazor CSS 熱重載支持 現在,你將能夠使用我們的新增功能在 Visual Studio 中使用每個更新試用一系列新功能。 選擇每個功能以瞭解有關特定功 ...
  • 需求如下,在DEV框架項目中,需要在表格中增加一列顯示圖片,並且能編輯該列圖片,然後進行保存等操作,最終效果如下 這裡使用的是PictureEdit控制項來實現,打開DEV GridControl設計器,在ColumnEdit選擇PictureEdit: 綁定圖片代碼如下: DataTable dtO ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...