question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Over 1000 gaps triggers Oracle "1000 elements in list" limitation

See original GitHub issue

The number of gaps in the events processed by a tracking event processor occasionally exceeds 1000, which triggers the Oracle limitation of maximum number of elements in an IN-clause. We would like a work-around in Axon Framework to handle this situation by splitting the IN-clause in as many IN-clauses as needed, concatenated by OR’s. We think the following code in org.axonframework.eventsourcing.eventstore.jdbc.JdbcEventStorageEngine (version 4.0.3) would do this:

    protected PreparedStatement readEventDataAxon(Connection connection, TrackingToken lastToken,
        int batchSize) throws SQLException {
        isTrue(lastToken == null || lastToken instanceof GapAwareTrackingToken,
            () -> format("Token [%s] is of the wrong type", lastToken));
        GapAwareTrackingToken previousToken = (GapAwareTrackingToken) lastToken;
        String sql = "SELECT " + trackedEventFields() + " FROM " + schema.domainEventTable() +
            " WHERE (" + schema.globalIndexColumn() + " > ? AND " + schema.globalIndexColumn() + " <= ?) ";
        List<Long> gaps;
        if (previousToken != null) {
            gaps = new ArrayList<>(previousToken.getGaps());
            if (!gaps.isEmpty()) {
//                sql += " OR " + schema.globalIndexColumn() + " IN (" +
//                    String.join(",", Collections.nCopies(gaps.size(), "?")) + ") ";
                final AtomicInteger counter = new AtomicInteger(0);
                sql += " OR " + Collections
                    .nCopies(gaps.size(), "?")
                    .stream()
                    .collect(Collectors.groupingBy(it -> counter.getAndIncrement() / 1000))
                    .values()
                    .stream()
                    .map(placeholders -> placeholders.stream().collect(Collectors.joining(", ", schema.globalIndexColumn() + " IN (", ")")))
                    .collect(Collectors.joining(" OR "));
            }
        } else {
            gaps = Collections.emptyList();
        }
        sql += "ORDER BY " + schema.globalIndexColumn() + " ASC";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        long globalIndex = previousToken == null ? -1 : previousToken.getIndex();
        preparedStatement.setLong(1, globalIndex);
        preparedStatement.setLong(2, globalIndex + batchSize);
        for (int i = 0; i < gaps.size(); i++) {
            preparedStatement.setLong(i + 3, gaps.get(i));
        }
        return preparedStatement;
    }

The same solution would be applicable to version 3.x.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
ericjanmalotauxcommented, Mar 5, 2019

Thanks @smcvb, that’s exactly what we are doing. At the same time we wanted to be good open source community citizens and offer our solution to whoever would benefit from it.

0reactions
abuijzecommented, Aug 7, 2019

This issue has been the subject of discussions several times, here. On one hand, we do see there are some optimizations that could be done in the framework. However, we feel that the root cause is in the occurrence of the high number of gaps, in the first place. Configuring the database to work with dedicated sequences for the Domain Event Entry table is a solution that targets the root cause. Ultimately, there is always the possibility to tweak the exact SQL statements performed by the Storage Engine to resolve database-specific issues that may arise.

Since there are enough alternatives, we have decided not to build anything specific into Axon to resolve this issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Limit and conversion very long IN list : WHERE x IN - Ask TOM
Oracle has the 1000 elements limit for IN lists for whatever reason (not very clear to me), but it does not enforce it...
Read more >
Problem with BULK COLLECT with million rows - Ask TOM
Use the LIMIT clause, bulk collect say 100 to 1000 rows -- process them, bulk insert them, get the next 100/1000 rows. You...
Read more >
varying elements in IN list - Ask TOM
varying elements in IN list I am using Oracle Report Builder 3.0.5.8.0 . While using bind refernce i have created a dynamic list...
Read more >
Remove 1000 limit on IN clause - Oracle Communities
In Oracle we can only put up to 1000 values into an IN clause. I would like to see this restriction dropped.
Read more >
ORA-01795: maximum number of expressions in a list is 1000 ...
when ever values specified for 'IN' operator in select statement exceeds 1000 then I am getting this error. How to over come this...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found