Бұл мақаланың ғылыми журналдағы нұсқасы мына жерде қолжетімді: Dapper vs EF Core: A Practical Performance Comparison in .NET
Source materials бар benchmark релизі мына жерде қолжетімді: efcore-vs-dapper v1.0.0
.NET-қосымшада data-access технологиясын таңдау - жай ғана жеке қалаудың мәселесі емес. Ол latency, memory allocations, garbage collector қысымы, maintainability, ал кейде жүктеме кезіндегі infrastructure cost көрсеткіштеріне де әсер етеді.
Көптеген enterprise .NET жүйелерінде таңдау көбіне екі танымал тәсілге келіп тіреледі:
- Entity Framework Core: productivity, LINQ queries, change tracking, migrations және жоғары деңгейлі persistence model беретін толыққанды ORM.
- Dapper: SQL-ге жақын қалдыратын және minimal abstraction арқылы fast mapping-ке фокусталатын жеңіл micro-ORM.
Әдеттегі жауап көбіне былай айтылады: “EF Core ыңғайлырақ, Dapper жылдамырақ”.
Бірақ айырмашылық қаншалықты үлкен? Және ол қай сценарийлерде шынымен маңызды?
Осы сұраққа жауап беру үшін біз EF Core мен Dapper-ді PostgreSQL, .NET және BenchmarkDotNet арқылы бірнеше реалистік read, join, update және parallel-query сценарийлерінде салыстырдық.
Тест ортасы
Benchmark PostgreSQL 17.6, .NET 10 және BenchmarkDotNet арқылы орындалды. Database controlled environment ішінде қайта құрылды, ал test data fixed seed арқылы deterministic түрде генерацияланды.
Мақсат isolated synthetic micro-operation өлшеу емес, data-access жолының реалистік end-to-end құнын бағалау болды:
- query construction;
- database round-trip;
- row materialization;
- objects ішіне mapping;
- memory allocation.
Тест схемасы products, orders және order_items бар шағын e-commerce domain ретінде құрылды.

Сурет 1. products, orders және order_items кестелері бар database schema.
Workload ішіне primary key бойынша single-row reads, filtered reads, әртүрлі table sizes үстіндегі paginated reads, JOIN көп қолданылатын order selection, simple updates, complex updates және жоғары concurrency бар parallel reads кірді.
Read scenarios үшін EF Core no-tracking queries режимінде бапталды, бұл unnecessary change tracking overhead азайту үшін жасалды. EF Core compiled queries бөлек variant ретінде де тестіленді.
Осы зерттеуге жасалған source-code review кезінде біз Dapper-дің asynchronous query path ішінде redundant nullable-conversion operation тауып, issue ретінде хабарладық. Бұл finding implementation-level observation ретінде ғана айтылған және benchmark evaluation ішіне кірмейді.
Dapper GitHub Issue #2184: Unused value in QueryAsync
Аллокациялар неге маңызды
Latency маңызды, бірақ .NET сияқты managed runtime үшін маңызды жалғыз метрика емес.
Егер data-access layer әр request үшін көбірек memory allocate етсе, ол memory кейін garbage collector арқылы тазалануы керек. Sustained load кезінде бұл GC frequency арттырып, tail latency нашарлатуы мүмкін.
Басқаша айтқанда, екі тәсіл average execution time бойынша жақын көрінсе де, memory allocation аз тәсіл production load кезінде болжамдырақ жұмыс істеуі мүмкін.
Сондықтан benchmark execution time мәнін microseconds per operation ретінде және managed memory allocations мәнін KB немесе MB per operation ретінде өлшеді.
Simple Read: Dapper-дің шағын, бірақ анық артықшылығы бар
Single-row product lookup сценарийінде Dapper EF Core baseline-пен салыстырғанда төмен execution time және төмен memory allocation көрсетті.
EF Core compiled queries read path жақсартты, бірақ allocation айырмашылығын толық жойған жоқ.

Сурет 2. Dapper, EF Core және EF Core compiled queries үшін SelectOneProduct execution time және memory allocation.
Бұл маңызды нәтиже, өйткені simple reads backend services ішінде жиі кездеседі. Бірақ мұндағы айырмашылық драмалық емес. Көптеген business applications үшін тек осы нәтиже EF Core-ды Dapper-ге ауыстыруға жеткіліксіз болуы мүмкін.
Қызығырақ нәтижелер query complexity өскен кезде пайда болады.
Bulk Reads: data volume өскен сайын айырмашылық азаяды
Көп products таңдаған кезде Dapper мен EF Core арасындағы relative difference total execution time өскен сайын кішірейе түсті.
Dapper benchmark ішінде әлі де жылдамырақ болды, бірақ күрделірек сценарийлермен салыстырғанда gap соншалықты үлкен болған жоқ.

Сурет 3. Selected records саны артқан сайын SelectNProducts execution time өсуі.
Бұл straightforward bulk reads кезінде database work және data transfer жалпы cost ішінде dominant болуы мүмкін екенін көрсетеді. ORM overhead әлі бар, бірақ total operation ішіндегі үлесі азаяды.
JOIN-heavy queries: Dapper алға шығады
Ең үлкен айырмашылық join-heavy queries кезінде байқалды.
Benchmark orders-ті олардың order items-пен бірге таңдады, яғни memory ішінде materialize жасалатын object graph көлемі өсті.
Дәл осы жерде EF Core көбірек жұмыс істейді. Ол LINQ-ті translate етеді, entities materialize жасайды, relationships өңдейді және internal state басқарады. No-tracking қосулы болса да, direct SQL mapping-пен салыстырғанда abstraction көбірек.
Ал Dapper explicit SQL орындайды және rows-ты simple objects ішіне аз internal machinery арқылы map етеді.

Сурет 4. Әртүрлі ItemsPerOrder мәндері үшін Dapper, EF Core және EF Core compiled queries бойынша SelectNOrders execution time.
Representative join-heavy scenario ішінде Dapper time advantage шамамен 51.2% болды.
Бұл EF Core нашар деген сөз емес. Бұл large object graphs және JOIN-heavy reads abstraction overhead көрінетін workload түрі екенін білдіреді.
Query complexity және speedup
Data volume мен query complexity арасындағы байланысты жақсырақ көрсету үшін біз speedup heat map қолдандық.
Speedup factor былай есептелді:
EF Core time / Dapper time
Яғни 2.0 мәні сол scenario ішінде EF Core Dapper-ге қарағанда шамамен екі есе ұзақ жұмыс істегенін білдіреді.

Сурет 5. Әртүрлі data volumes және ItemsPerOrder мәндері бойынша speedup factor.
Heat map pattern-ді анық көрсетеді: query complexity өскен сайын Dapper көбірек benefit алады, әсіресе көбірек rows join және materialize жасау керек болғанда.
Parallel Reads: аллокациялар маңыздырақ бола бастайды
Benchmark degree of parallelism 128 болатын high-concurrency read scenario-ны да қамтыды.
Бұл жағдайда EF Core мен Dapper execution time бойынша дерлік бірдей болды. Dapper-дің time advantage тек шамамен 0.5% болды.
Бірақ memory allocation басқа картинаны көрсетті.
Dapper contention кезінде аз memory allocate етті, бұл бір уақытта көп requests өңдейтін real services үшін маңызды болуы мүмкін.

Сурет 6. DOP = 128 кезіндегі parallel selection үшін memory allocation.
Бұл негізгі takeaways бірі: performance тек mean latency емес. Allocation pressure garbage collection, response-time variance және production stability көрсеткіштеріне әсер етуі мүмкін.
Нәтижелер summary
Benchmark execution time және memory allocations екеуін де ескеретін combined performance index қолданды. Бұл index тек жылдамырақ емес, memory-efficient тәсілдерге де артықшылық берді.
| Scenario | Dapper Time Advantage | PI Dapper | PI EF Core Compiled |
|---|---|---|---|
| SelectOne simple | 8.4% | 1.5 | 1.3 |
| SelectOne with filter | 16.4% | 1.66 | 1.43 |
| SelectN, 1000 records | 6.7% | 1.16 | 1.03 |
| SelectN with JOIN | 51.2% | 2.28 | 0.97 |
| UpdateOne simple | 31.6% | 1.97 | 1.28 |
| UpdateOne complex | 48.3% | 2.5 | 1.3 |
| Parallel query, DOP = 128 | 0.5% | 1.12 | 1.0 |
Dapper-дің ең үлкен артықшылықтары join-heavy selection, complex updates және allocation-sensitive parallel workloads ішінде көрінді.
Бұл архитектура үшін нені білдіреді
Қорытынды “әрқашан Dapper қолданыңыз” деген емес.
Дұрысы:
Workload-қа сәйкес келетін data-access approach таңдаңыз.
EF Core productivity, maintainability, migrations, rich domain modeling және change tracking әр allocation үшін күрестен маңыздырақ болған кезде күшті таңдау.
Dapper latency-sensitive paths, large read models, JOIN-heavy queries, high allocation pressure немесе толық бақылауды қажет ететін explicit SQL бар қолданбалар үшін күшті таңдау.
Практикада көптеген жүйелер екеуін де қолдана алады.
Мысалы:
- Maintainability маңыздырақ administrative CRUD, internal tools және business workflows үшін EF Core қолдану.
- Query shape үстінен full control қажет hot read paths, reporting queries, high-throughput endpoints және complex SQL үшін Dapper қолдану.
Мұндай hybrid approach бүкіл system бойынша бір технологияны мәжбүрлеп қолданғаннан жиі реалистілеу.
EF Core compiled queries көмектеседі, бірақ толық емес
EF Core compiled queries кейбір read scenarios ішінде overhead азайтты, бірақ allocation profile-ды түбегейлі өзгерткен жоқ.
Себебі query compilation - EF Core cost ішіндегі бір ғана бөлік.
Басқа costs қалады:
- entity materialization;
- relationship handling;
- change tracking configuration;
- state management;
- abstraction overhead.
Compiled queries пайдалы, бірақ олар EF Core-ды Dapper-ге айналдыратын magic switch емес.
Dapper жылдамырақ, бірақ тегін емес
Dapper көбірек control береді, бірақ ол control responsibility-мен бірге келеді.
Dapper қолданғанда developers SQL correctness, parameterization, mapping discipline, schema changes, duplicated query logic, transaction boundaries және SQL мен application models арасындағы consistency мәселелерін өздері басқаруы керек.
EF Core ішінде бұл concerns-тің көбін framework шешеді. Dapper қолданғанда олар team responsibility болып қалады.
Сондықтан architectural trade-off анық:
Dapper runtime overhead азайта алады, ал EF Core development overhead азайта алады.
Дұрыс таңдау сіздің system үшін қай cost маңыздырақ екеніне байланысты.
Final Takeaway
Біздің benchmark ішінде Dapper managed allocations тұрақты түрде азайтты және mean latency жиі жақсартты. Ең үлкен benefits complex object graph retrieval және update scenarios ішінде көрінді.
EF Core compiled queries кейбір read paths жақсартты, бірақ tested configuration ішінде memory allocation мәнін айтарлықтай азайтқан жоқ.
Performance-critical .NET services үшін, әсіресе high load жағдайында, data-access technology әдет немесе preference бойынша емес, actual workload characteristics негізінде таңдалуы керек.
Егер негізгі constraint developer productivity болса, EF Core әдетте жақсы default.
Егер негізгі constraint memory pressure, latency stability немесе complex SQL performance болса, Dapper-ді seriously consideration жасау керек.
Ең практикалық architecture көбіне EF Core versus Dapper емес.
Ол abstraction көмектесетін жерде EF Core, ал control маңызды жерде Dapper қолдану.