main.dart 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import 'dart:io';
  2. import 'package:dart_duckdb/dart_duckdb.dart' as duck;
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/services.dart';
  5. import 'package:path_provider/path_provider.dart';
  6. import 'package:sqlite3/sqlite3.dart' as sqlite;
  7. void main() async {
  8. WidgetsFlutterBinding.ensureInitialized();
  9. await copyDB("poetry.db");
  10. await copyDB("poetry.duck.db");
  11. runApp(const MyApp());
  12. }
  13. Future<void> copyDB(String filename) async {
  14. ByteData data = await rootBundle.load('assets/db/$filename');
  15. List<int> bytes = data.buffer.asUint8List(
  16. data.offsetInBytes,
  17. data.lengthInBytes,
  18. );
  19. var base = (await getApplicationDocumentsDirectory()).path;
  20. await File("$base/$filename").writeAsBytes(bytes);
  21. }
  22. class MyApp extends StatelessWidget {
  23. const MyApp({super.key});
  24. @override
  25. Widget build(BuildContext context) {
  26. return MaterialApp(
  27. title: 'DB Benchmark',
  28. theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true),
  29. home: const MyHomePage(title: 'DB Benchmark'));
  30. }
  31. }
  32. class MyHomePage extends StatefulWidget {
  33. const MyHomePage({super.key, required this.title});
  34. final String title;
  35. @override
  36. State<MyHomePage> createState() => _MyHomePageState();
  37. }
  38. class _MyHomePageState extends State<MyHomePage> {
  39. sqlite.Database? db;
  40. duck.Database? duckdb;
  41. duck.Connection? connection;
  42. int _sqliteLikeTime = 0;
  43. int _sqliteLikeResult = 0;
  44. int _duckdbLikeTime = 0;
  45. int _duckdbLikeResult = 0;
  46. List<List<Object?>>? _sqliteResult;
  47. List<List<dynamic>>? _duckdbResult;
  48. void _like() {
  49. var sql = Stopwatch();
  50. sql.start();
  51. var sqlResultSet = db!.select('SELECT * FROM poetry WHERE author LIKE ? LIMIT 10 OFFSET 1000', ['王%']);
  52. sql.stop();
  53. var duck = Stopwatch();
  54. duck.start();
  55. var duckResultSet = connection!.query('SELECT * FROM poetry WHERE author LIKE \'王%\' LIMIT 10 OFFSET 1000').fetchAll();
  56. duck.stop();
  57. setState(() {
  58. _sqliteLikeResult = sqlResultSet.length;
  59. _sqliteLikeTime = sql.elapsedMilliseconds;
  60. _sqliteResult = sqlResultSet.rows;
  61. _duckdbLikeResult = duckResultSet.length;
  62. _duckdbLikeTime = duck.elapsedMilliseconds;
  63. _duckdbResult = duckResultSet;
  64. });
  65. }
  66. void _fts() {
  67. db!.execute("delete from poetry where id like 'mayan-test-%'");
  68. connection!.execute("delete from poetry where id like 'mayan-test-%'");
  69. var sql = Stopwatch();
  70. sql.start();
  71. final stmt = db!.prepare('INSERT INTO poetry (id,title,author,content) VALUES (?,?,?,?)');
  72. for (var i = 0; i < 1000; i++) {
  73. stmt.execute(['mayan-test-$i', 'title', 'author', 'content']);
  74. }
  75. stmt.dispose();
  76. sql.stop();
  77. var duck = Stopwatch();
  78. duck.start();
  79. final prepared = connection!.prepare("INSERT INTO poetry (id,title,author,content) VALUES (?,?,?,?)");
  80. for (var i = 0; i < 1000; i++) {
  81. prepared.bindParams(['mayan-test-$i', 'title', 'author', 'content']);
  82. prepared.execute();
  83. }
  84. duck.stop();
  85. setState(() {
  86. _sqliteLikeResult = 1000;
  87. _sqliteLikeTime = sql.elapsedMilliseconds;
  88. _duckdbLikeResult = 1000;
  89. _duckdbLikeTime = duck.elapsedMilliseconds;
  90. });
  91. }
  92. @override
  93. void initState() {
  94. getApplicationDocumentsDirectory().then((dir) {
  95. var base = dir.path;
  96. db ??= sqlite.sqlite3.open('$base/poetry.db');
  97. duckdb ??= duck.duckdb.open("$base/poetry.duck.db");
  98. connection ??= duck.duckdb.connect(duckdb!);
  99. });
  100. super.initState();
  101. }
  102. @override
  103. void dispose() {
  104. db!.dispose();
  105. connection!.dispose();
  106. duckdb!.dispose();
  107. super.dispose();
  108. }
  109. @override
  110. Widget build(BuildContext context) {
  111. return Scaffold(
  112. appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title)),
  113. body: Column(children: [
  114. Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
  115. InkWell(onTap: _like, child: const Text("QUERY", style: TextStyle(fontSize: 50))),
  116. InkWell(onTap: _fts, child: const Text("WRITE", style: TextStyle(fontSize: 50)))
  117. ]),
  118. Container(height: 1, color: Colors.grey, margin: const EdgeInsets.symmetric(vertical: 5)),
  119. const Row(
  120. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  121. children: [Text("sqlite结果数"), Text("sqlite时长"), Text("duckdb结果数"), Text("duckdb时长")]),
  122. Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
  123. Text(_sqliteLikeResult.toString()),
  124. Text(_sqliteLikeTime.toString()),
  125. Text(_duckdbLikeResult.toString()),
  126. Text(_duckdbLikeTime.toString())
  127. ]),
  128. Row(children: [
  129. Expanded(child: Column(children: _sqliteResult?.map((r) => Text("${r[1]} - ${r[2]}")).toList()??[])),
  130. SizedBox(width: 60),
  131. Expanded(child: Column(children: _duckdbResult?.map((r) => Text("${r[1]} - ${r[2]}")).toList()??[]))
  132. ])
  133. ]));
  134. }
  135. }