Skip to content

Commit

Permalink
Remove writeMany(singleStatement)
Browse files Browse the repository at this point in the history
as the performance gains evaporated once the index-update was fixed

Perf test:
```
flutter: Case: singleStatement=false, largeValue=false, batchSize=1000
flutter: 1000 x `write` took 483.64ms
flutter: `writeMany` took 8.07ms
flutter: `writeMany` again took 14.23ms

flutter: Case: singleStatement=true, largeValue=false, batchSize=1000
flutter: 1000 x `write` took 501.32ms
flutter: `writeMany` took 9.61ms
flutter: `writeMany` again took 13.23ms
```
  • Loading branch information
tp committed Dec 2, 2024
1 parent 36c2187 commit e571cf3
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 329 deletions.
2 changes: 0 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
## 2.0.1

* Add tests for internal schema migrations
* Speed up `writeMany` by defaulting to use a single statement for all inserts (as opposed to a single transactions with many individual inserts)
* One can revert to the previous behavior by setting `singleStatement: false` in the call
* Add `delete(where: )` to delete all rows matching a specific index-query

## 2.0.0
Expand Down
169 changes: 0 additions & 169 deletions example/perf/write_many.dart

This file was deleted.

5 changes: 0 additions & 5 deletions example/run_perf.sh

This file was deleted.

101 changes: 14 additions & 87 deletions lib/src/index_entity_store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -238,79 +238,33 @@ class IndexedEntityStore<T, K> {
_handleUpdate({_connector.getPrimaryKey(e)});
}

/// Insert or update many entities in a single batch
/// Insert or update many entities in a single transaction
///
/// Notification for changes will only fire after all changes have been written (meaning queries will get a single update after all writes are finished)
void writeMany(
Iterable<T> entities, {
bool singleStatement = true,
}) {
void writeMany(Iterable<T> entities) {
final keys = <K>{};

final sw = Stopwatch()..start();

if (singleStatement) {
if (entities.isEmpty) {
return;
}

try {
_database.execute('BEGIN');
try {
_database.execute('BEGIN');
assert(_database.autocommit == false);

_database.execute(
[
'REPLACE INTO `entity` (`type`, `key`, `value`) '
' VALUES (?1, ?, ?)',
// Add additional entry values for each further parameter
', (?1, ?, ?)' * (entities.length - 1),
].join(' '),
[
_entityKey,
for (final e in entities) ...[
_connector.getPrimaryKey(e),
_connector.serialize(e),
],
],
for (final e in entities) {
_entityInsertStatement.execute(
[_entityKey, _connector.getPrimaryKey(e), _connector.serialize(e)],
);

_updateIndexInternalSingleStatement(entities);
_updateIndexInternal(e);

_database.execute('COMMIT');
} catch (e) {
_database.execute('ROLLBACK');

rethrow;
keys.add(_connector.getPrimaryKey(e));
}

keys.addAll(entities.map(_connector.getPrimaryKey));
} else {
// transaction variant

try {
_database.execute('BEGIN');
assert(_database.autocommit == false);

for (final e in entities) {
_entityInsertStatement.execute(
[_entityKey, _connector.getPrimaryKey(e), _connector.serialize(e)],
);

_updateIndexInternal(e);

keys.add(_connector.getPrimaryKey(e));
}

_database.execute('COMMIT');
} catch (e) {
_database.execute('ROLLBACK');
_database.execute('COMMIT');
} catch (e) {
_database.execute('ROLLBACK');

rethrow;
}
rethrow;
}

print(
'$singleStatement ${(sw.elapsedMicroseconds / 1000).toStringAsFixed(2)}ms');

_handleUpdate(keys);
}

Expand All @@ -334,33 +288,6 @@ class IndexedEntityStore<T, K> {
}
}

void _updateIndexInternalSingleStatement(Iterable<T> entities) {
if (_indexColumns._indexColumns.values.isEmpty) {
return;
}

_database.execute(
[
'INSERT INTO `index` (`type`, `entity`, `field`, `value`, `referenced_type`, `unique`) '
' VALUES (?1, ?, ?, ?, ?, ?)',
// Add additional entry values for each further entity
', (?1, ?, ?, ?, ?, ?)' *
(entities.length * _indexColumns._indexColumns.values.length - 1),
].join(' '),
[
_entityKey,
for (final indexColumn in _indexColumns._indexColumns.values)
for (final e in entities) ...[
_connector.getPrimaryKey(e),
indexColumn._field,
indexColumn._getIndexValue(e),
indexColumn._referencedEntity,
indexColumn._unique,
],
],
);
}

/// Delete the specified entries
void delete({
final T? entity,
Expand Down
Loading

0 comments on commit e571cf3

Please sign in to comment.