Speed Comparison: Dapper vs Entity Framework

A few months ago I ran across a blog post about getting started with Dapper.NET. I had heard of Dapper before but had never actually tried to use it. Dapper is known for being fast, but I was curious just how much faster it would be in the situations I typically find myself: writing database queries. I’ve long used Entity Framework for data layers, which is often criticized for being slow.

To test out Dapper’s speed, I built four basic tests so I could compare its performance to Entity Framework. If you’d like to run these experiments yourself, all the code used for this blog post is available on GitHub.

Data Model

The data model is relatively small and simple. I’ve worked on a few projects involving athletes so that was my starting point.

[sourcecode language=”plain”]

public class Athlete
{
public long Id { get; set;}

public string FirstName { get; set; }

public string LastName { get; set; }

public string Position { get; set; }
}

[/sourcecode]

An athlete is nothing without a team, which leads to the next class.

[sourcecode language=”plain”]
public class Team
{
public long Id { get; set; }

public string Name { get; set; }
}

[/sourcecode]

An athlete can, of course, be on multiple teams so a third class is needed to link the two.

I’ve never had a good experience when using Entity Framework to manage the relationships between objects, so there are no navigation properties on these objects. They are a straight mapping of class to database table. I mostly use ORMs to reduce the amount of SQL I write, not necessarily to manage the relationships between my objects.

Test Setup

Before starting any tests, I seeded my database with three sports teams with each containing 1,000 athletes. The first thing I found was both Entity Framework and Dapper take longer with the first query than with subsequent queries. For Entity Framework, I know a query has to be complied on the first execution, but for Dapper I’m not sure what it’s doing during the first execution. For all tests, I ran each query twice and ran each test 10 times before averaging out the results. All times are in milliseconds.

Loading 1 Athlete

In the first test, I loaded a single athlete by Id from the database.

Test Iteration

Entity Framework First

Entity Framework Second

Dapper First

Dapper Second

1

348

13

83

6

2

361

15

81

5

3

332

13

67

6

4

312

11

67

6

5

313

14

69

6

6

334

14

69

6

7

368

12

75

7

8

331

13

72

9

9

333

13

72

6

10

321

14

69

8

Average (ms)

335.3

13.1

72.6

6.7

There’s no denying that Dapper is faster than Entity Framework, especially on the first execution. Compiling the LINQ query is an expensive event.

Loading Many Athletes by Position

In the second test, I loaded all the athletes for a specific position to see how each framework fared loading multiple records and searching on a string field instead of a primary key.

Test Iteration

Entity Framework First

Entity Framework Second

Dapper First

Dapper Second

1

80

35

13

7

2

83

33

19

10

3

81

33

12

8

4

75

33

11

7

5

69

33

11

7

6

79

33

11

7

7

78

38

12

7

8

72

32

12

8

9

76

32

12

8

10

65

34

14

6

Average (ms)

75.8

33.8

12.7

7.5

The differences between the first and second queries were less extreme for the second test. My suspicion is both frameworks are mapping the database on the first query and pay an extra time penalty. Loading more results also increased the gap in speed between the second Entity Framework and Dapper queries.

Loading Teams with Athletes

I wanted to see how well each framework would handle joins which led to the third test: loading a team with all 1,000 athletes.

Test Iteration

Entity Framework First

Entity Framework Second

Dapper First

Dapper Second

1

143

38

23

16

2

144

42

27

20

3

127

39

21

16

4

132

29

21

26

5

136

38

28

22

6

142

37

24

20

7

132

35

22

16

8

133

39

22

16

9

127

36

24

18

10

121

37

21

21

Average (ms)

133.7

37

23.3

19.1

The results are pretty consistent with the other tests. Entity Framework is still lagging behind, but there was a Dapper run that took longer on the second query rather than the first. On average though the second Dapper query still ran 4.2 milliseconds faster.

Inserting Athletes

In the last test, I wanted to look at the speed differences inserting records into the database. I inserted one athlete at a time and for Dapper I used the Dapper-Extensions nuget package to handle the insert. The package reduces an insert to a single method call. In the past, the insert code I’ve seen has always looked a little weird and was one of my main complaints about Dapper.

Test Iteration

Entity Framework First

Entity Framework Second

Dapper First

Dapper Second

1

284

14

85

6

2

278

11

91

7

3

252

12

83

5

4

249

11

106

6

5

268

10

76

7

6

268

10

80

8

7

266

12

92

6

8

267

13

86

8

9

256

11

80

7

10

253

11

78

6

Average (ms)

264.1

11.5

85.7

6.6

Surprisingly, the first Dapper queries took around as long as the first queries for loading a single athlete. I don’t know enough about the internals of the Dapper-Extensions, but it seems likely there is an additional step taken when using its insert functionality. Otherwise the results are consistent with the trends seen across the other tests.

Conclusion

Dapper was written with speed as a priority and the tests definitely prove this out. However, if we ignore the overhead of the first query, the difference between the two ranged from 5-25 milliseconds. The largest site I know of using Dapper is Stack Overflow and I would think they definitely benefit from saving milliseconds anywhere they can. In a smaller application I’m not sure it makes sense to make an ORM decision solely for the sake of a few milliseconds. Instead I would pick based on the style of the code written for either framework. I like Entity Framework for its LINQ integration and will continue to favor it for that. To me using Dapper felt like writing SQL, which I try to avoid when possible.

In the past when a query starts to take too long executing through Entity Framework I have replaced it with either a view or a stored procedure, depending on the situation. Going forward, Dapper will be a valuable tool that could be used before going straight to raw SQL.