Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/include/optimizer/projection_push_down_optimizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class ProjectionPushDownOptimizer : public LogicalOperatorVisitor {
void visitMerge(planner::LogicalOperator* op) override;
void visitCopyFrom(planner::LogicalOperator* op) override;
void visitTableFunctionCall(planner::LogicalOperator*) override;
void visitScanNodeTable(planner::LogicalOperator*) override;

void visitSetInfo(const binder::BoundSetPropertyInfo& info);
void visitInsertInfo(const planner::LogicalInsertInfo& info);
Expand All @@ -57,6 +58,8 @@ class ProjectionPushDownOptimizer : public LogicalOperatorVisitor {
void preAppendProjection(planner::LogicalOperator* op, common::idx_t childIdx,
binder::expression_vector expressions);

bool clearScanNodeTableProperties(planner::LogicalOperator* op) const;

private:
binder::expression_set propertiesInUse;
binder::expression_set variablesInUse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class LogicalScanNodeTable final : public LogicalOperator {
std::shared_ptr<binder::Expression> getNodeID() const { return nodeID; }
std::vector<common::table_id_t> getTableIDs() const { return nodeTableIDs; }

void clearProperty() { properties.clear(); }
binder::expression_vector getProperties() const { return properties; }
void addProperty(std::shared_ptr<binder::Expression> expr) {
properties.push_back(std::move(expr));
Expand Down
33 changes: 31 additions & 2 deletions src/optimizer/projection_push_down_optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "planner/operator/persistent/logical_insert.h"
#include "planner/operator/persistent/logical_merge.h"
#include "planner/operator/persistent/logical_set.h"
#include <planner/operator/scan/logical_scan_node_table.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change <> to "" for consistency


using namespace kuzu::common;
using namespace kuzu::planner;
Expand Down Expand Up @@ -266,6 +267,28 @@ void ProjectionPushDownOptimizer::visitTableFunctionCall(LogicalOperator* op) {
tableFunctionCall.setColumnSkips(std::move(columnSkips));
}

void ProjectionPushDownOptimizer::visitScanNodeTable(LogicalOperator* op) {
clearScanNodeTableProperties(op);
}

bool ProjectionPushDownOptimizer::clearScanNodeTableProperties(planner::LogicalOperator* op) const {
auto& scanNodeTable = op->cast<LogicalScanNodeTable>();
if (scanNodeTable.getProperties().empty()) {
return false;
}
bool hasPropertiesInUse = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First I wanna understand on which query this optimization will take effect so that we can add test & benchmark.

Second, I think we can do better than clearProperty. Scan operator can scan a subset of its current properties.

for (auto expression : scanNodeTable.getProperties()) {
if (propertiesInUse.contains(expression)) {
hasPropertiesInUse = true;
break;
}
}
if (!hasPropertiesInUse) {
scanNodeTable.clearProperty();
}
return !hasPropertiesInUse;
}

void ProjectionPushDownOptimizer::visitSetInfo(const binder::BoundSetPropertyInfo& info) {
switch (info.tableType) {
case TableType::NODE: {
Expand Down Expand Up @@ -361,8 +384,14 @@ void ProjectionPushDownOptimizer::preAppendProjection(LogicalOperator* op, idx_t
// We don't have a way to handle
return;
}
auto projection =
std::make_shared<LogicalProjection>(std::move(expressions), op->getChild(childIdx));
auto child = op->getChild(childIdx);
// reset scan node table properties
if (child->getOperatorType() == LogicalOperatorType::SCAN_NODE_TABLE) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a new optimizer that remove any unnecessary projection instead of coupling the logic inside projection push down optimizer.

if (clearScanNodeTableProperties(child.get())) {
return;
}
}
auto projection = std::make_shared<LogicalProjection>(std::move(expressions), child);
projection->computeFlatSchema();
op->setChild(childIdx, std::move(projection));
}
Expand Down
21 changes: 16 additions & 5 deletions src/processor/operator/scan/primary_key_scan_node_table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ std::string PrimaryKeyScanPrintInfo::toString() const {
result += ",Alias: ";
result += alias;
}
result += ", Expressions: ";
result += binder::ExpressionUtil::toString(expressions);

if (!expressions.empty()) {
result += ", Expressions: ";
result += binder::ExpressionUtil::toString(expressions);
}
return result;
}

Expand All @@ -36,8 +37,18 @@ void PrimaryKeyScanNodeTable::initLocalStateInternal(ResultSet* resultSet,
for (auto& pos : info.outVectorsPos) {
outVectors.push_back(resultSet->getValueVector(pos).get());
}
scanState = std::make_unique<NodeTableScanState>(
resultSet->getValueVector(info.nodeIDPos).get(), outVectors, outVectors[0]->state);
if (outVectors.empty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ray6080 should review this.


scanState =
std::make_unique<NodeTableScanState>(resultSet->getValueVector(info.nodeIDPos).get(),
outVectors, DataChunkState::getSingleValueDataChunkState());

;
} else {

scanState = std::make_unique<NodeTableScanState>(
resultSet->getValueVector(info.nodeIDPos).get(), outVectors, outVectors[0]->state);
}
indexEvaluator->init(*resultSet, context->clientContext);
}

Expand Down