Skip to content

Commit

Permalink
Make query planning of index scans fast again (#1674)
Browse files Browse the repository at this point in the history
Since #1619, the size estimate for an index scan always involved one or several copies of the block metadata, which incurred a significant query planning cost for most queries. Now, such a copy is only made for an index scan followed by a `FILTER` and only the metadata of those blocks is copied, which remain after the `FILTER` (in which case the two operations are expensive anyway).
  • Loading branch information
joka921 authored Dec 12, 2024
1 parent 0400f90 commit 4a15994
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 20 deletions.
32 changes: 17 additions & 15 deletions src/engine/IndexScan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,24 +339,26 @@ IndexScan::getBlockMetadata() const {
// _____________________________________________________________________________
std::optional<std::vector<CompressedBlockMetadata>>
IndexScan::getBlockMetadataOptionallyPrefiltered() const {
// The code after this is expensive because it always copies the complete
// block metadata, so we do an early return of `nullopt` (which means "use all
// the blocks") if no prefilter is specified.
if (!prefilter_.has_value()) {
return std::nullopt;
}
auto optBlockSpan = getBlockMetadata();
std::optional<std::vector<CompressedBlockMetadata>> optBlocks = std::nullopt;
if (optBlockSpan.has_value()) {
const auto& blockSpan = optBlockSpan.value();
optBlocks = {blockSpan.begin(), blockSpan.end()};
applyPrefilterIfPossible(optBlocks.value());
if (!optBlockSpan.has_value()) {
return std::nullopt;
}
return optBlocks;
return applyPrefilter(optBlockSpan.value());
}

// _____________________________________________________________________________
void IndexScan::applyPrefilterIfPossible(
std::vector<CompressedBlockMetadata>& blocks) const {
if (prefilter_.has_value()) {
// Apply the prefilter on given blocks.
auto& [prefilterExpr, columnIndex] = prefilter_.value();
blocks = prefilterExpr->evaluate(blocks, columnIndex);
}
std::vector<CompressedBlockMetadata> IndexScan::applyPrefilter(
std::span<const CompressedBlockMetadata> blocks) const {
AD_CORRECTNESS_CHECK(prefilter_.has_value() && getLimit().isUnconstrained());
// Apply the prefilter on given blocks.
auto& [prefilterExpr, columnIndex] = prefilter_.value();
return prefilterExpr->evaluate(blocks, columnIndex);
}

// _____________________________________________________________________________
Expand All @@ -369,12 +371,12 @@ Permutation::IdTableGenerator IndexScan::getLazyScan(
auto filteredBlocks = getLimit().isUnconstrained()
? std::optional(std::move(blocks))
: std::nullopt;
if (filteredBlocks.has_value()) {
if (filteredBlocks.has_value() && prefilter_.has_value()) {
// Note: The prefilter expression applied with applyPrefilterIfPossible()
// is not related to the prefilter procedure mentioned in the comment above.
// If this IndexScan owns a <PrefilterExpression, ColumnIdx> pair, it can
// be applied.
applyPrefilterIfPossible(filteredBlocks.value());
filteredBlocks = applyPrefilter(filteredBlocks.value());
}
return getScanPermutation().lazyScan(getScanSpecification(), filteredBlocks,
additionalColumns(), cancellationHandle_,
Expand Down
9 changes: 4 additions & 5 deletions src/engine/IndexScan.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,10 @@ class IndexScan final : public Operation {
std::optional<std::vector<CompressedBlockMetadata>>
getBlockMetadataOptionallyPrefiltered() const;

// If `isUnconstrained()` yields true, return the blocks as given or the
// prefiltered blocks (if `prefilter_` has value). If `isUnconstrained()` is
// false, return `std::nullopt`.
void applyPrefilterIfPossible(
std::vector<CompressedBlockMetadata>& blocks) const;
// Apply the `prefilter_` to the `blocks`. May only be called if the limit is
// unconstrained, and a `prefilter_` exists.
std::vector<CompressedBlockMetadata> applyPrefilter(
std::span<const CompressedBlockMetadata> blocks) const;

// Helper functions for the public `getLazyScanFor...` methods and
// `chunkedIndexScan` (see above).
Expand Down

0 comments on commit 4a15994

Please sign in to comment.