Skip to content

tortoise/orm-benchmarks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ORM Benchmarks

Qualification criteria is:

  • Needs to support minimum 2 databases, e.g. sqlite + something-else
  • Runs on Python3.7
  • Actively developed
  • Has ability to generate initial DDL off specified models
  • Handle one-to-many relationships

Benchmarks:

These benchmarks are not meant to be used as a direct comparison. They suffer from co-operative back-off, and is a lot simpler than common real-world scenarios.

Tests:

  1. Insert: Single (single entry at a time)
  2. Insert: Batch (many batched in a transaction)
  3. Insert: Bulk (using bulk insert operations)
  4. Filter: Large (a large result set)
  5. Filter: Small (a limit 20 with random offset)
  6. Get
  7. Filter: dict
  8. Filter: tuple
  9. Update: Whole (update the whole object)
  10. Update: Partial (update only a single field of the whole object)
  11. Delete

1) Small table, no relations

model Journal:
    id: autonumber primary key
    timestamp: datetime → now()
    level: small int(enum) → 10/20/30/40/50 (indexed)
    text: varchar(255) → A selection of text (indexed)

2) Small table, with relations

model Journal:
    id: autonumber primary key
    timestamp: datetime → now()
    level: small int(enum) → 10/20/30/40/50 (indexed)
    text: varchar(255) → A selection of text (indexed)

    parent: FK to parent BigTree
    child: reverse-FB to parent BigTree
    knows: M2M to BigTree

3) Large table

model BigTree:
    id: uuid primary key
    created_at: datetime → initial-now()
    updated_at: datetime → always-now()
    level: small int(enum) → 10/20/30/40/50 (indexed)
    text: varchar(255) → A selection of text (indexed)

    # Repeated 2 times with defaults, another 2 times as optional:
    col_float: double
    col_smallint: small integer
    col_int: integer
    col_bigint: big integer
    col_char: char(255)
    col_text: text
    col_decimal: decimal(12,8)
    col_json: json

ORMs:

Django:

https://www.djangoproject.com/

Pros:

  • Provides all the essential features
  • Simple, clean, API
  • Great test framework
  • Excellent documentation
  • Migrations done right™

Cons:

  • Brings whole Django along with it
peewee:

https://github.com/coleifer/peewee

Pony ORM:

https://github.com/ponyorm/pony

Pros:

  • Fast
  • Does cacheing automatically

Cons:

  • Does not support bulk insert.
SQLAlchemy ORM:

http://www.sqlalchemy.org/

Pros:

  • The "de facto" ORM in the python world
  • Supports just about every feature and edge case
  • Documentation re DB quirks is excellent

Cons:

  • Complicated, layers upon layers of leaky abstractions
  • You have to manage transactions manually
  • You have to write a script to get DDL SQL
  • Documentation expects you to be intimate with SQLAlchemy
  • Migrations are add ons
SQLObject:

https://github.com/sqlobject/sqlobject

  • Does not support 16-bit integer for level, used 32-bit instead.
  • Does not support bulk insert.
Tortoise ORM:

https://github.com/tortoise/tortoise-orm

  • Currently the only async ORM as part of this suite.
  • Disclaimer: I'm an active contributor to this project

Results (SQLite)

Results for SQLite, using the SHM in-memory filesystem on Linux, to try and make the tests more CPU limited, but still do FS round-trips. Also more consistent than an SSD.

Py39:

Test 1 Django peewee Pony ORM SQLAlchemy ORM SQLObject Tortoise ORM Max Best ORM
Insert: Single

1497.95

4872.62

1644.55

976.67

1420.88

5347.90

5347.90

Tortoise ORM
Insert: Batch

4479.47

6113.61

17873.20

8009.59

4134.64

6585.81

17873.20

Pony ORM

Insert: Bulk

16263.30

19282.38

17151.81

22266.31

22266.31

Tortoise ORM
Filter: Large

72808.51

37053.46

113551.38

77921.94

30458.51

31078.13

113551.38

Pony ORM

Filter: Small

27091.89

21447.86

14085.46

26718.01

28338.93

18595.55

28338.93

SQLObject

Get

3297.72

3342.47

7482.68

3335.06

6650.92

3286.47

7482.68

Pony ORM

Filter: dict

98377.01

42442.45

91354.29

72774.82

37338.13

98377.01

Django

Filter: tuple

104145.07

44562.58

111963.06

120148.50

35421.57

120148.50

SQLAlchemy ORM
Update: Whole

4390.65

5908.89

23083.68

16193.39

12167.63

8778.30

23083.68

Pony ORM

Update: Partial

4799.47

7789.01

31692.20

29134.53

23880.80

10027.27

31692.20

Pony ORM

Delete

4923.51

10720.91

47743.93

46426.27

1602.24

10481.33

47743.93

Pony ORM

Geometric Mean

12016.85

12731.01

25699.52

19750.85

7934.03

13016.58

30488.23

Pony ORM

Test 2 Django peewee Pony ORM SQLAlchemy ORM SQLObject Tortoise ORM Max Best ORM
Insert: Single

1375.24

4739.11

1560.53

826.58

1360.56

5235.68

5235.68

Tortoise ORM
Insert: Batch

4214.45

6076.06

13350.85

2710.25

4431.66

6643.60

13350.85

Pony ORM

Insert: Bulk

14587.36

18580.24

9334.37

20513.05

20513.05

Tortoise ORM
Filter: Large

70246.54

34803.17

107677.40

68477.31

29510.34

29973.02

107677.40

Pony ORM

Filter: Small

25822.56

18710.87

14796.78

21498.59

26458.48

18192.33

26458.48

SQLObject

Get

3061.19

3254.31

8124.48

2930.53

6272.33

3238.39

8124.48

Pony ORM

Filter: dict

92273.77

45158.31

82152.66

63156.77

37411.62

92273.77

Django

Filter: tuple

92140.65

43432.18

107504.91

104278.85

34485.92

107504.91

Pony ORM

Update: Whole

4041.05

5293.05

22296.49

12227.82

11964.75

8385.37

22296.49

Pony ORM

Update: Partial

4718.18

7761.19

32753.93

18142.24

23089.39

8583.97

32753.93

Pony ORM

Delete

949.35

10826.34

15739.36

1126.62

1258.04

7853.74

15739.36

Pony ORM

Geometric Mean

9708.83

12316.1

22066.86

10365.98

7523.29

12234.09

26072.4

Pony ORM

Test 3 Django peewee Pony ORM SQLAlchemy ORM SQLObject Tortoise ORM Max Best ORM
Insert: Single

1158.99

2579.05

1341.74

795.49

1010.96

3012.69

3012.69

Tortoise ORM
Insert: Batch

2565.09

2814.82

5110.64

5135.04

2652.73

3816.79

5135.04

SQLAlchemy ORM
Insert: Bulk

3899.39

7228.57

11383.03

7544.93

11383.03

SQLAlchemy ORM
Filter: Large

23726.12

12886.49

45353.88

32007.81

16424.68

13818.28

45353.88

Pony ORM

Filter: Small

12567.48

7681.68

4872.43

16312.17

15380.60

10183.42

16312.17

SQLAlchemy ORM
Get

1780.10

1121.88

5418.16

2838.25

3760.11

2064.30

5418.16

Pony ORM

Filter: dict

30270.60

18113.41

23406.96

26928.97

15463.37

30270.60

Django

Filter: tuple

32982.30

18634.59

45589.27

39613.25

14293.40

45589.27

Pony ORM

Update: Whole

2520.12

1460.37

16595.00

13253.82

10368.59

4979.73

16595.00

Pony ORM

Update: Partial

4281.07

7621.57

21649.70

21192.27

22376.78

8353.98

22376.78

SQLObject

Delete

4725.69

10672.44

39093.15

38714.27

1436.19

8972.24

39093.15

Pony ORM

Geometric Mean

5920.37

5764.76

12853.14

12079.92

5509.39

7032.0

15685.54

Pony ORM

PyPy7.3-Py3.6: (Outdated)

Test 1 Django peewee Pony ORM SQLAlchemy ORM Tortoise ORM
Insert: Single

4092.94

6042.45

6166.89

1004.98

6786.58

Insert: Batch

4529.93

6456.81

18247.22

6982.63

26348.64

Insert: Bulk

17961.11

24302.27

21428.22

80531.38

Filter: Large

152801.52

91886.54

295678.67

129700.40

90993.88

Filter: Small

6099.36

65094.77

175134.68

60966.19

45463.05

Get

4255.07

6793.41

8310.16

4339.15

9229.52

Filter: dict

147533.08

116293.38

215108.01

109211.59

94985.63

Filter: tuple

175529.83

122951.45

281181.48

253415.27

130914.54

Update: Whole

6710.01

16514.91

41939.12

22677.70

30434.61

Update: Partial

8089.69

23377.04

51308.13

43023.59

38576.48

Delete

8766.41

29169.88

74799.44

81948.65

42805.28

Geometric Mean

15887.12

27270.66

58524.96

28825.51

39281.41

Test 2 Django peewee Pony ORM SQLAlchemy ORM Tortoise ORM
Insert: Single

4089.62

5982.16

5927.49

818.31

8128.96

Insert: Batch

4582.76

6909.47

15558.25

6012.19

25381.23

Insert: Bulk

16201.10

24021.67

20294.09

77993.66

Filter: Large

138968.39

90818.94

279382.51

118860.29

71640.16

Filter: Small

5439.62

62951.57

168192.03

52251.13

38208.34

Get

4092.11

6989.34

8230.02

3379.57

8430.82

Filter: dict

134900.00

112626.68

202932.98

94477.51

71689.52

Filter: tuple

159685.66

122797.29

274293.13

223882.76

119104.10

Update: Whole

6201.26

11396.24

35644.86

17562.70

28303.72

Update: Partial

7669.88

23086.17

41247.77

25492.40

35430.58

Delete

2087.76

34330.64

38098.81

633.66

369.97

Geometric Mean

13135.78

26719.72

50653.72

15519.07

23445.05

Test 3 Django peewee Pony ORM SQLAlchemy ORM Tortoise ORM
Insert: Single

2194.07

3827.50

4030.12

792.54

5429.88

Insert: Batch

2072.86

3928.59

7509.87

4841.25

15489.04

Insert: Bulk

4747.82

9996.01

15407.30

29085.53

Filter: Large

25016.73

30627.76

122459.86

37727.96

2968.21

Filter: Small

1508.74

24123.13

98162.15

21523.32

2454.28

Get

2231.56

4443.86

6313.33

2312.70

1490.23

Filter: dict

29467.52

40064.73

81433.44

27085.70

3001.12

Filter: tuple

31329.65

46774.06

123617.06

45894.78

8845.51

Update: Whole

4220.60

6984.34

29109.60

10686.28

11302.96

Update: Partial

7346.76

21125.93

33835.74

14716.48

24182.52

Delete

9083.28

31221.47

64601.85

64029.41

41709.27

Geometric Mean

6146.34

14064.74

32867.64

12702.84

7951.76

Results (PostgreSQL)

PostgreSQL 14.2 on my iMac.

Test 1 Django peewee Pony ORM SQLAlchemy ORM SQLObject Tortoise ORM Max Best ORM
Insert: Single

2697.46

2350.95

1438.77

1528.94

2391.13

2127.20

2697.46

Django

Insert: Batch

3275.14

2845.78

4710.80

4742.43

2911.46

10351.19

10351.19

Tortoise ORM
Insert: Bulk

10283.94

12309.04

8018.63

6395.90

12309.04

peewee

Filter: Large

82726.80

63288.60

131699.63

58844.30

50097.69

60394.02

131699.63

Pony ORM

Filter: Small

21555.97

21030.33

15793.05

20046.59

38191.14

27055.55

38191.14

SQLObject

Get

2407.95

2351.78

4403.82

2303.46

5057.52

3289.33

5057.52

SQLObject

Filter: dict

98132.27

84224.66

102139.41

60221.74

84444.54

102139.41

Pony ORM

Filter: tuple

106625.81

85903.08

136295.97

88605.19

80993.53

136295.97

Pony ORM

Update: Whole

2921.10

2971.09

4567.47

6585.60

3444.53

15486.60

15486.60

Tortoise ORM
Update: Partial

2797.47

4698.24

8153.30

9595.10

7100.51

18292.88

18292.88

Tortoise ORM
Delete

3068.43

4037.09

10634.38

9627.40

3026.73

20908.43

20908.43

Tortoise ORM
Geometric Mean

10021.18

10045.33

14237.59

11602.3

6874.29

16828.99

22424.22

Tortoise ORM
Test 2 Django peewee Pony ORM SQLAlchemy ORM SQLObject Tortoise ORM Max Best ORM
Insert: Single

2539.09

2328.50

1411.27

1224.83

2251.15

6191.22

6191.22

Tortoise ORM
Insert: Batch

3047.01

2868.06

4822.54

4451.61

2329.81

11730.02

11730.02

Tortoise ORM
Insert: Bulk

10221.78

13097.38

5323.13

24089.97

24089.97

Tortoise ORM
Filter: Large

76022.33

56985.76

129987.42

55025.55

48907.18

66584.00

129987.42

Pony ORM

Filter: Small

25138.05

23036.83

13473.45

15691.13

35394.67

29498.84

35394.67

SQLObject

Get

2369.76

2428.95

6715.08

2186.10

4299.78

3345.98

6715.08

Pony ORM

Filter: dict

89768.94

77124.33

94526.98

52507.12

84390.74

94526.98

Pony ORM

Filter: tuple

93446.95

76994.08

133410.86

76779.38

76248.52

133410.86

Pony ORM

Update: Whole

2624.86

3177.50

6538.28

4518.49

4239.80

13470.83

13470.83

Tortoise ORM
Update: Partial

2755.20

4391.80

7717.85

6744.77

8232.20

17027.82

17027.82

Tortoise ORM
Delete

705.78

6002.87

6820.62

780.78

1502.48

18380.23

18380.23

Tortoise ORM
Geometric Mean

8432.77

10302.12

14258.86

7650.52

6150.27

20779.73

25428.1

Tortoise ORM
Test 3 Django peewee Pony ORM SQLAlchemy ORM SQLObject Tortoise ORM Max Best ORM
Insert: Single

1659.56

1337.22

1072.47

1197.89

1362.25

2057.49

2057.49

Tortoise ORM
Insert: Batch

1926.09

1720.19

2476.65

3928.80

1634.21

5382.42

5382.42

Tortoise ORM
Insert: Bulk

4083.48

4813.74

5169.09

8218.97

8218.97

Tortoise ORM
Filter: Large

29212.11

15313.77

46597.16

28275.76

23833.91

25190.86

46597.16

Pony ORM

Filter: Small

11936.52

7643.78

6958.63

10994.92

19048.65

14186.21

19048.65

SQLObject

Get

1481.25

905.49

3998.63

1917.48

3190.46

2247.54

3998.63

Pony ORM

Filter: dict

30291.07

22944.69

24043.02

24225.81

28221.54

30291.07

Django

Filter: tuple

37316.20

24910.94

48191.83

35775.67

27661.74

48191.83

Pony ORM

Update: Whole

1660.00

1141.62

5982.29

4790.04

4137.46

7815.69

7815.69

Tortoise ORM
Update: Partial

2902.67

4413.85

6453.72

7099.40

8381.57

17360.03

17360.03

Tortoise ORM
Delete

3392.16

6421.26

10231.13

8968.32

2034.67

19775.12

19775.12

Tortoise ORM
Geometric Mean

5444.3

4644.73

8313.06

7434.18

4673.36

10394.95

12595.03

Tortoise ORM

Results (MySQL)

MySQL 8.0.28 on my iMac.

Test 1 Django peewee Pony ORM SQLAlchemy ORM SQLObject Tortoise ORM Max Best ORM
Insert: Single

1209.92

1001.09

1053.19

1347.27

1908.04

6876.58

6876.58

Tortoise ORM
Insert: Batch

749.83

2558.92

3963.25

1530.72

2953.42

9431.34

9431.34

Tortoise ORM
Insert: Bulk

3987.40

12345.27

10112.36

22422.24

22422.24

Tortoise ORM
Filter: Large

49227.96

57264.03

87150.75

58957.62

46543.39

48015.57

87150.75

Pony ORM

Filter: Small

14872.76

16482.54

4844.00

16099.81

33623.56

27429.86

33623.56

SQLObject

Get

1955.32

2397.74

4140.78

2462.82

4124.88

3611.48

4140.78

Pony ORM

Filter: dict

56656.05

70404.15

60058.48

51717.04

56083.08

70404.15

peewee

Filter: tuple

55412.78

71583.70

86158.07

76517.45

52624.17

86158.07

Pony ORM

Update: Whole

2166.47

1924.82

4370.82

6054.75

3347.90

11290.19

11290.19

Tortoise ORM
Update: Partial

2699.93

4266.03

7172.51

10429.35

8004.78

13482.17

13482.17

Tortoise ORM
Delete

2852.52

4261.78

7971.99

11119.38

1466.69

15008.68

15008.68

Tortoise ORM
Geometric Mean

5843.52

8284.89

9942.11

10279.79

5880.45

17482.86

20324.93

Tortoise ORM
Test 2 Django peewee Pony ORM SQLAlchemy ORM SQLObject Tortoise ORM Max Best ORM
Insert: Single

1635.09

1211.99

1503.17

1193.35

1833.09

6608.95

6608.95

Tortoise ORM
Insert: Batch

2169.06

3424.20

3730.49

3134.71

2808.82

9012.26

9012.26

Tortoise ORM
Insert: Bulk

5156.00

12022.20

6509.26

19639.93

19639.93

Tortoise ORM
Filter: Large

47022.58

50669.92

90269.00

53166.04

42782.43

46612.01

90269.00

Pony ORM

Filter: Small

13620.37

19250.93

7432.71

15309.16

32922.06

26025.83

32922.06

SQLObject

Get

1810.18

1743.56

5457.96

2251.67

5029.05

3303.88

5457.96

Pony ORM

Filter: dict

52659.40

64137.99

71828.88

50016.54

49126.48

71828.88

Pony ORM

Filter: tuple

52679.69

65446.35

90069.34

72336.37

50094.20

90069.34

Pony ORM

Update: Whole

2347.67

1706.10

5001.29

5288.58

3714.30

10855.70

10855.70

Tortoise ORM
Update: Partial

2446.26

4068.74

6731.51

8148.18

7689.34

13793.14

13793.14

Tortoise ORM
Delete

611.18

5633.39

5323.53

805.95

1113.54

15653.61

15653.61

Tortoise ORM
Geometric Mean

5700.18

8359.38

10906.27

7695.76

5728.65

16637.86

20627.76

Tortoise ORM
Test 3 Django peewee Pony ORM SQLAlchemy ORM SQLObject Tortoise ORM Max Best ORM
Insert: Single

1161.88

1197.36

868.83

1080.28

1200.52

3517.80

3517.80

Tortoise ORM
Insert: Batch

1136.71

1782.50

2086.51

2289.90

1775.70

4093.84

4093.84

Tortoise ORM
Insert: Bulk

2947.01

4774.88

5026.13

6676.91

6676.91

Tortoise ORM
Filter: Large

21409.92

15339.61

42885.45

26865.84

22947.41

17383.94

42885.45

Pony ORM

Filter: Small

7377.32

7753.80

5326.22

11604.61

18188.73

9937.04

18188.73

SQLObject

Get

912.97

897.40

3436.21

1932.07

2808.04

1647.64

3436.21

Pony ORM

Filter: dict

23786.67

18481.91

20365.59

23747.48

17939.35

23786.67

Django

Filter: tuple

29319.45

9438.12

42158.68

33278.53

16991.10

42158.68

Pony ORM

Update: Whole

1572.93

1061.51

3674.52

5221.10

3289.43

3302.92

5221.10

SQLAlchemy ORM
Update: Partial

2348.49

3900.11

5711.35

7318.67

7214.52

4440.85

7318.67

SQLAlchemy ORM
Delete

2464.61

5020.07

6816.90

9002.52

1637.52

6402.34

9002.52

SQLAlchemy ORM
Geometric Mean

3941.19

3977.64

6671.87

7018.64

4201.45

6434.92

9893.7

SQLAlchemy ORM

PyPy7.3-Py3.6: (Outdated)

Test 1 Django peewee Pony ORM SQLAlchemy ORM Tortoise ORM
Insert: Single

2479.55

2663.10

3088.68

686.92

3311.91

Insert: Batch

3478.12

4571.76

5194.87

4214.03

13584.52

Insert: Bulk

14553.90

19480.48

15260.41

55214.98

Filter: Large

80983.35

175029.85

479457.80

59215.04

160185.46

Filter: Small

4995.72

37628.16

136060.23

18990.66

24888.53

Get

2868.25

4870.54

6107.97

2630.39

6538.67

Filter: dict

80650.88

219339.95

301358.89

52242.19

183104.50

Filter: tuple

93584.59

257332.26

490594.29

74740.17

175407.06

Update: Whole

3563.43

7760.36

5348.80

5540.23

11161.77

Update: Partial

4536.02

10036.94

11210.07

12264.97

14984.03

Delete

4978.72

10073.98

11107.52

10907.25

12449.24

Geometric Mean

9889.22

20926.09

30192.66

11285.31

26393.92

Test 2 Django peewee Pony ORM SQLAlchemy ORM Tortoise ORM
Insert: Single

2266.32

2663.82

2669.34

597.25

3513.88

Insert: Batch

3328.18

4435.96

6949.97

3773.89

10493.08

Insert: Bulk

14065.42

18684.71

14458.93

55861.34

Filter: Large

80296.63

164763.64

447302.97

54498.39

153077.80

Filter: Small

4800.15

35434.65

130211.62

17627.65

21258.96

Get

2565.44

4543.19

5849.48

2310.20

6251.27

Filter: dict

77842.51

207108.12

280970.71

50958.86

185933.49

Filter: tuple

91267.58

239574.53

438762.04

73630.97

172285.95

Update: Whole

2701.75

5406.82

6975.43

4327.97

9913.26

Update: Partial

4539.54

9879.36

10746.90

10125.79

14495.50

Delete

1176.44

7017.19

6249.98

1387.88

8181.26

Geometric Mean

8165.06

18884.27

28591.56

8489.41

24079.39

Test 3 Django peewee Pony ORM SQLAlchemy ORM Tortoise ORM
Insert: Single

1008.08

1582.11

1617.94

465.03

2258.82

Insert: Batch

1492.21

2833.39

3595.88

2126.38

6739.82

Insert: Bulk

3357.71

6484.93

6410.32

16790.12

Filter: Large

12164.83

40576.68

109275.41

9531.62

34746.82

Filter: Small

2314.81

12551.29

58031.65

5503.53

9873.51

Get

1083.01

2165.71

2800.69

854.14

2358.51

Filter: dict

12742.82

54209.15

73098.84

8640.37

46526.40

Filter: tuple

13728.33

62009.01

107794.63

10255.39

42013.15

Update: Whole

1589.21

2352.14

4388.50

3946.67

5021.95

Update: Partial

3894.78

8822.50

6142.39

7243.80

14487.33

Delete

3791.23

8238.25

8413.57

8394.18

11540.60

Geometric Mean

3367.9

8574.74

13385.55

4134.8

11175.14

Quick analysis

  • Pony ORM is heavily optimised for performance.
  • Django & SQLAlchemy is surprisingly similar in performance.
  • Tortoise ORM is competitive.
  • Get is surprisingly slow for everyone.
  • Pony ORM, SQLAlchemy & SQLObject does merge operations for updates, so is technically always partial updates.
  • Tortoise ORM performance using the asyncpg PostgreSQL driver is really good, winning overall.
  • Tortoise ORM performance using the aiomysql MySQL driver is mediocre, the driver itself is taking the majority of CPU time. PyPy runs this driver a lot faster, which indicates that the slow paths are likely just in Python itself.

PyPy comparison: SQLite

  • peewee and Pony ORM gets a noticeable performance improvement
  • SQLAlchemy ORM and Django performs similarily
  • Tortoise ORM has slow Reads and fast Create, Update & Delete operation
  • SQLObject fails

PyPy comparison: MySQL

  • peewee and Tortoise ORM gets a noticeable performance improvement
  • Pony ORM is marginally faster
  • SQLAlchemy ORM and Django is marginally slower
  • SQLObject fails

Performance of Tortoise

Versions

Note that these benchmarks have since changed, so state is not exactly the same as above. This should only be used as a "guideline" of the improvement in performance since we started with the performance optimization process.

Tortoise ORM: v0.10.6 v0.10.7 v0.10.8 v0.10.9 v0.10.11 v0.11.3 v0.12.1
Seedup (Insert & Big & Small)

19.4, 1.5, 6.1

25.9, 2.0, 6.6

81.8, 2.2, 8.7

95.3, 2.4, 13.1

118.2, 2.7, 14.6 136.9, 2.4, 13.5
===================== ============== ================ ================ ================ ================ ================ ================
Insert

89.89

2180.38

2933.19

7635.42

8297.53

9870.59

14544.81

Insert: atomic

149.59

2481.16

3275.53

11966.53

14791.36

18452.56

18245.26

Insert: bulk

71124.01

Filter: match

55866.14

101035.06

139482.12

158997.41

165398.56

186298.75

160746.73

Filter: contains

76803.14

100536.06

128669.50

142954.66

167127.12

177623.78

159116.08

Filter: limit 20

4583.53

27830.14

29995.23

39170.17

58740.05

65742.82

60285.42

Get

233.69

1868.15

2136.20

2818.41

4411.01

4899.04

5208.50

Perf issues identified from profiling

  • base.executor._field_to_db() could be replaced with a pre-computed dict lookup
  • Queryset.resolve_filters is doing lots of unnecessary stuff, especially for .get() method
  • Get operation is slow (likely slow SQL generation, could be resolved with parametrized query cacheing)

On Queryset performance

Since pypika is immutable, and our Queryset object is as well, we need tests to guarantee our immutability. Then we can aggresively cache querysets.

Also, we can make more queries use parameterised queries, cache SQL generation, and cache prepared queries.

It seems in cases where we can cache the PyPika result (and use prepared statements), PyPy performance increase is even larger than CPython.

Perf fixes applied

  1. aiosqlite polling misalignment (sqlite specific)

    (20-40% speedup for retrieval, 10× — 15× speedup for insertion): omnilib/aiosqlite#12

  2. pypika improved copy implementation (generic)

    (53% speedup for insertion): kayak/pypika#160

  3. tortoise.models.__init__ restructure (generic)

    (25-30% speedup for retrieval) tortoise/tortoise-orm#51

  4. tortoise.models.__init__ restructure (generic)

    (9-11% speedup for retrieval) tortoise/tortoise-orm#52

  5. aiosqlite macros (sqlite specific)

    (1-5% speedup for retrieval, 10-40% speedup for insertion) omnilib/aiosqlite#13

  6. Simple prepared insert statements (generic)

    (35-250% speedup for insertion) omnilib/aiosqlite#13 tortoise/tortoise-orm#54

  7. pre-generate initial pypika query object per model (generic)

    (25-50% speedup for small fetch operations) tortoise/tortoise-orm#54

  8. pre-generate filter map, and standard select for all values per model (generic)

    (15-30% speedup for small fetch operations) tortoise/tortoise-orm#64

  9. More optimal queryset cloning (generic)

    (6-15% speedup for small fetch operations) tortoise/tortoise-orm#64

  10. pypika improved copy implementation (generic)

    (10-15% speedup for small fetch operations) kayak/pypika#205

  11. Optimised inserts/updates & Bulk create (generic)

    (5-40% speedup for small insert operations)
    (350-600% speedup for bulk insert over small insert operations) tortoise/tortoise-orm#142
  12. De-lazied some metadata objects & More efficient queryset manipulation (generic)

    (15-25% speedup for large fetch operations)
    (5-30% speedup for small fetches) tortoise/tortoise-orm#158
  13. Parametrized delete/update (generic)

    (260-280% speedup for delete operations)
    (300-600% speedup for update operations) tortoise/tortoise-orm#177
  14. Lazy Relation properties (generic)

    (15~140% speedup for all on Test 2 (Small & Relational)) tortoise/tortoise-orm#187

  15. Know about default converters & native DB types (generic)

    (20-25% speedup for Fetch operations) tortoise/tortoise-orm#190

  16. Connection Pooling (MySQL & PostgreSQL)

    (30-50% speedup overall) tortoise/tortoise-orm#229

  17. Many small tweaks (generic)

    (5-30% depending on driver) tortoise/tortoise-orm#241