diff --git a/.gitignore b/.gitignore
index 9778b6c6df6ee16d1e4cd6b7fbe2e2cf33709065..fa004f2817cd534b73939b457e916cafdb71441e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,5 +9,4 @@ perf/perf.data*
 perf/perf.folded
 perf/perf.unfold
 perf/*.svg
-perf/test_db
-pref/sorted_results.txt
\ No newline at end of file
+perf/test_db
\ No newline at end of file
diff --git a/src/execution/execution_sort.h b/src/execution/execution_sort.h
index 49ac0be01f84740fcf42b1a6d3e5b9de2c093296..66d0c755dbd2d33c6cedf08f4ca81ca447391c36 100644
--- a/src/execution/execution_sort.h
+++ b/src/execution/execution_sort.h
@@ -59,7 +59,11 @@ public:
         it_ = recs_.begin();
     }
 
-    void nextTuple() override { ++it_; }
+    void nextTuple() override {
+        if (is_end())
+            return;
+        ++it_;
+    }
 
     std::unique_ptr<RmRecord> Next() override {
         if (is_end())
diff --git a/src/execution/executor_block_nestedloop_join.h b/src/execution/executor_block_nestedloop_join.h
index e41ac250d913b055ba19adcacf653b92d0e47298..f6ce6ee7ad46ed6607ec2249cf20b92d856cdd35 100644
--- a/src/execution/executor_block_nestedloop_join.h
+++ b/src/execution/executor_block_nestedloop_join.h
@@ -5,7 +5,7 @@
 #include "index/ix.h"
 #include "system/sm.h"
 
-#define MAX_BUFFER_SIZE 1000
+#define MAX_BUFFER_SIZE 10000
 
 class JoinBuffer {
 private:
@@ -204,6 +204,8 @@ public:
     }
 
     void nextTuple() override {
+        if (is_end())
+            return;
         // 跳过上一个符合条件的Tuple
         goNext();
         nextMatch();
diff --git a/src/execution/executor_external_sort.h b/src/execution/executor_external_sort.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c9a4beadbdbbb21fa51e063f6b1cda5e2173336
--- /dev/null
+++ b/src/execution/executor_external_sort.h
@@ -0,0 +1,174 @@
+#include "execution_defs.h"
+#include "execution_manager.h"
+#include "executor_abstract.h"
+#include "index/ix.h"
+#include "record_printer.h"
+#include "system/sm.h"
+#include <functional>
+#include <queue>
+
+#define MAX_BLOCK_SIZE 1000
+
+class ExternalSortExecutor : public AbstractExecutor {
+private:
+    std::unique_ptr<AbstractExecutor> prev_; // 上一层
+    std::string name_;                       // 上一层名称
+    std::vector<ColMeta> sel_cols_;          // 排序用到的列
+    size_t len_;                             // 每条记录的长度
+
+    std::vector<Rid> start_rids_;                // 排序后每个子表开始位置
+    std::vector<std::unique_ptr<RmScan>> scans_; // 迭代器
+    size_t tuple_cnt_;                           // tuple总数
+    size_t tuple_used_;                          // 已被取出的tuple数
+
+    std::priority_queue<std::pair<size_t, RmRecord>, std::vector<std::pair<size_t, RmRecord>>,
+                        std::function<bool(const std::pair<size_t, RmRecord>&, const std::pair<size_t, RmRecord>&)>>
+        pq_;                                                    // 多路归并用
+    std::function<bool(const RmRecord&, const RmRecord&)> cmp_; // 内排序使用的cmp
+
+    RmManager* rm_manager_;
+    BufferPoolManager* buffer_pool_manager_;
+    std::unique_ptr<RmFileHandle> file_handle_;
+
+public:
+    ExternalSortExecutor(std::unique_ptr<AbstractExecutor> prev, std::vector<ColMeta> sel_cols, SmManager* sm_manager,
+                         Context* context) {
+        prev_ = std::move(prev);
+        sel_cols_ = std::move(sel_cols);
+        name_ = sel_cols_[0].tab_name + "_sorted";
+        len_ = prev_->tupleLen();
+
+        tuple_cnt_ = 0;
+        tuple_used_ = 0;
+
+        cmp_ = [&](const RmRecord& a, const RmRecord& b) -> bool {
+            for (auto it = sel_cols_.begin(); it != sel_cols_.end(); ++it) {
+                int op = comp_lhs_rhs(it->type, a.data + it->offset, it->type, b.data + it->offset, it->len, it->len);
+                if (op == -1)
+                    return true;
+                if (op == 1)
+                    return false;
+            }
+            return false;
+        };
+
+        std::priority_queue<std::pair<size_t, RmRecord>, std::vector<std::pair<size_t, RmRecord>>,
+                            std::function<bool(const std::pair<size_t, RmRecord>&, const std::pair<size_t, RmRecord>&)>>
+        pq([&](const std::pair<size_t, RmRecord>& a, const std::pair<size_t, RmRecord>& b) -> bool {
+            for (auto it = sel_cols_.begin(); it != sel_cols_.end(); ++it) {
+                int op = comp_lhs_rhs(it->type, a.second.data + it->offset, it->type, b.second.data + it->offset,
+                                      it->len, it->len);
+                if (op == 1)
+                    return true;
+                if (op == -1)
+                    return false;
+            }
+            return false;
+        });
+
+        pq_ = std::move(pq);
+
+        rm_manager_ = sm_manager->get_rm_manager();
+        buffer_pool_manager_ = sm_manager->get_bpm();
+
+        file_handle_ = nullptr;
+        context_ = context;
+    }
+
+    ~ExternalSortExecutor() {
+        if (file_handle_) {
+            rm_manager_->close_file(file_handle_.get());
+            buffer_pool_manager_->delete_pages(file_handle_->GetFd());
+            rm_manager_->destroy_file(name_);
+        }
+        file_handle_ = nullptr;
+    }
+
+    ColMeta get_col_offset(const TabCol& target) { return prev_->get_col_offset(target); }
+
+    const std::vector<ColMeta>& cols() const { return prev_->cols(); }
+
+    bool is_end() const { return tuple_used_ == tuple_cnt_; }
+
+    size_t tupleLen() const { return len_; }
+
+    Rid& rid() override { return _abstract_rid; }
+
+    void beginTuple() override {
+        // 创建临时表
+        if (file_handle_) {
+            rm_manager_->close_file(file_handle_.get());
+            buffer_pool_manager_->delete_pages(file_handle_->GetFd());
+            rm_manager_->destroy_file(name_);
+        }
+        rm_manager_->create_file(name_, len_);
+        file_handle_ = rm_manager_->open_file(name_);
+
+        // 初始化变量
+        while (!pq_.empty()) {
+            pq_.pop();
+        }
+        tuple_cnt_ = 0;
+        tuple_used_ = 0;
+        start_rids_.clear();
+        scans_.clear();
+
+        std::vector<RmRecord> temp_recs;
+        temp_recs.reserve(MAX_BLOCK_SIZE);
+
+        // 分块排序
+        for (prev_->beginTuple(); !prev_->is_end(); prev_->nextTuple()) {
+            auto rec = prev_->Next();
+            temp_recs.push_back(*rec);
+            if (temp_recs.size() == MAX_BLOCK_SIZE) {
+                std::sort(temp_recs.begin(), temp_recs.end(), cmp_);
+                for (auto& temp_rec : temp_recs) {
+                    Rid rid = file_handle_->insert_record(temp_rec.data, context_);
+                    if (tuple_cnt_++ % MAX_BLOCK_SIZE == 0) {
+                        start_rids_.push_back(rid);
+                        scans_.emplace_back(std::move(std::make_unique<RmScan>(file_handle_.get())));
+                        scans_.back()->setRid(rid);
+                    }
+                }
+                temp_recs.clear();
+            }
+        }
+        if (!temp_recs.empty()) {
+            std::sort(temp_recs.begin(), temp_recs.end(), cmp_);
+            for (auto& temp_rec : temp_recs) {
+                Rid rid = file_handle_->insert_record(temp_rec.data, context_);
+                if (tuple_cnt_++ % MAX_BLOCK_SIZE == 0) {
+                    start_rids_.push_back(rid);
+                    scans_.emplace_back(std::move(std::make_unique<RmScan>(file_handle_.get())));
+                    scans_.back()->setRid(rid);
+                }
+            }
+        }
+
+        // 指向第一个符合条件的Tuple
+        int idx = 0;
+        for (auto& scan : scans_) {
+            pq_.push(std::make_pair(idx++, *file_handle_->get_record(scan->rid(), context_)));
+            scan->next();
+        }
+        start_rids_.push_back({-1, -1});
+    }
+
+    void nextTuple() override {
+        if (is_end())
+            return;
+        tuple_used_++;
+        size_t idx = pq_.top().first;
+        pq_.pop();
+        if (scans_[idx]->rid() != start_rids_[idx + 1]) {
+            pq_.push(std::make_pair(idx, *file_handle_->get_record(scans_[idx]->rid(), context_)));
+            scans_[idx]->next();
+        }
+    }
+
+    std::unique_ptr<RmRecord> Next() override {
+        if (is_end())
+            return nullptr;
+        return std::make_unique<RmRecord>(pq_.top().second);
+    }
+};
\ No newline at end of file
diff --git a/src/execution/executor_group.h b/src/execution/executor_group.h
index eb4cc2e7a2fa2adeeb062f2ec85bbb453224164d..4e7ca4a8af1ed5752c857a3ee49f7597761c9043 100644
--- a/src/execution/executor_group.h
+++ b/src/execution/executor_group.h
@@ -192,6 +192,8 @@ public:
     }
 
     void nextTuple() override {
+        if (is_end())
+            return;
         // 跳过上一个符合条件的Tuple
         ++scan_idx_;
         nextMatch();
diff --git a/src/execution/executor_index_scan.h b/src/execution/executor_index_scan.h
index 461c6af4d859ef641d049823026a26f8428da5c1..48f6092d181e5b7f79b195d14a252163e4463ea3 100644
--- a/src/execution/executor_index_scan.h
+++ b/src/execution/executor_index_scan.h
@@ -173,12 +173,19 @@ public:
     }
 
     void nextTuple() override {
+        if (is_end())
+            return;
         // 跳过上一个符合条件的Tuple
         scan_->next();
         nextMatch();
     }
 
-    std::unique_ptr<RmRecord> Next() override { return std::move(rec_); }
+    std::unique_ptr<RmRecord> Next() override {
+        // 考虑到存在调用nextTuple()前调用多次Next()的情况
+        RmRecord rec(len_, fh_->get_record(scan_->rid(), context_)->data);
+        return std::make_unique<RmRecord>(rec);
+        // return std::move(rec_);
+    }
 
     bool is_end() const override {
         if (isend_) {
diff --git a/src/execution/executor_join_where.h b/src/execution/executor_join_where.h
index 6e1744b2b7b2a62fe13ffd1e165e4f5b688b1d4b..8daefd139d8cf72e398128e7b5acbcbec81d2c71 100644
--- a/src/execution/executor_join_where.h
+++ b/src/execution/executor_join_where.h
@@ -87,6 +87,8 @@ public:
     }
 
     void nextTuple() override {
+        if (is_end())
+            return;
         // 跳过上一个符合条件的Tuple
         prev_->nextTuple();
         nextMatch();
diff --git a/src/execution/executor_nestedloop_join.h b/src/execution/executor_nestedloop_join.h
index 013cb1beb22fb8d5f904c10f372e305bdc001731..7af74763f092e6425b411b0107250ce8d3daea04 100644
--- a/src/execution/executor_nestedloop_join.h
+++ b/src/execution/executor_nestedloop_join.h
@@ -127,6 +127,8 @@ public:
     }
 
     void nextTuple() override {
+        if (is_end())
+            return;
         // 跳过上一个符合条件的Tuple
         goNext();
         nextMatch();
diff --git a/src/execution/executor_seq_scan.h b/src/execution/executor_seq_scan.h
index 287b227ea3c93955ad214bc5ab249220eb00c537..5f6399b78ef62d3b3138af841e441b183bd6c26b 100644
--- a/src/execution/executor_seq_scan.h
+++ b/src/execution/executor_seq_scan.h
@@ -114,6 +114,8 @@ public:
     }
 
     void nextTuple() override {
+        if (is_end())
+            return;
         // 跳过上一个符合条件的Tuple
         scan_->next();
         nextMatch();
diff --git a/src/execution/executor_sortmerge_join.h b/src/execution/executor_sortmerge_join.h
index 8e3725ba4f56a5c32f0c8e172c9ae7fd54fa091a..6601be51a216c5a3f77aafa0cb7ba5c795627e2b 100644
--- a/src/execution/executor_sortmerge_join.h
+++ b/src/execution/executor_sortmerge_join.h
@@ -2,6 +2,7 @@
 #include "execution_defs.h"
 #include "execution_manager.h"
 #include "executor_abstract.h"
+#include "executor_external_sort.h"
 #include "index/ix.h"
 #include "record_printer.h"
 #include "system/sm.h"
@@ -18,16 +19,17 @@ private:
     bool isend;
     bool is_exist_index_;
 
-    std::vector<RmRecord> left_recs_;  // 左表记录
-    std::vector<RmRecord> right_recs_; // 右表记录
-    std::vector<RmRecord>::iterator left_it_;
+    std::vector<RmRecord> right_recs_; // 右表相同记录
     std::vector<RmRecord>::iterator right_it_;
-    std::vector<RmRecord>::iterator right_start_; // 右表重复元组起点
-    std::vector<RmRecord>::iterator right_end_;   // 右表重复元组终点
+    bool has_match; // 左表是否已经匹配上右表
+
+    SmManager* sm_manager_;
 
 public:
     SortMergeJoinExecutor(std::unique_ptr<AbstractExecutor> left, std::unique_ptr<AbstractExecutor> right,
-                          std::vector<Condition> conds, JoinType type, bool is_exist_index, Context* context) {
+                          std::vector<Condition> conds, JoinType type, bool is_exist_index, SmManager* sm_manager,
+                          Context* context) {
+        sm_manager_ = sm_manager;
         left_ = std::move(left);
         right_ = std::move(right);
         len_ = left_->tupleLen() + right_->tupleLen();
@@ -44,7 +46,7 @@ public:
         for (auto& cond : fed_conds_) {
             if (cond.is_rhs_val)
                 continue;
-            auto left = std::find_if(cols_.begin(), cols_.end(), [&](ColMeta& a) {
+            auto left = std::find_if(cols_.begin(), cols_.end(), [&](const ColMeta& a) {
                 return a.tab_name == cond.lhs_col.tab_name && a.name == cond.lhs_col.col_name;
             });
             if (left->offset >= left_->tupleLen()) {
@@ -55,6 +57,30 @@ public:
         type_ = type;
         is_exist_index_ = is_exist_index;
         context_ = context;
+
+        // 没有索引,需要外排序
+        if (!is_exist_index_) {
+            std::vector<ColMeta> sel_cols_left;
+            std::vector<ColMeta> sel_cols_right;
+            for (auto& cond : fed_conds_) {
+                if (cond.is_rhs_val)
+                    continue;
+                auto left = std::find_if(cols_.begin(), cols_.end(), [&](const ColMeta& a) {
+                    return a.tab_name == cond.lhs_col.tab_name && a.name == cond.lhs_col.col_name;
+                });
+                sel_cols_left.push_back(*left);
+                auto right = std::find_if(cols_.begin(), cols_.end(), [&](const ColMeta& a) {
+                    return a.tab_name == cond.rhs_col.tab_name && a.name == cond.rhs_col.col_name;
+                });
+                right->offset -= left_->tupleLen();
+                sel_cols_right.push_back(*right);
+                right->offset += left_->tupleLen();
+            }
+            left_ = std::make_unique<ExternalSortExecutor>(std::move(left_), std::move(sel_cols_left), sm_manager_,
+                                                           context_);
+            right_ = std::make_unique<ExternalSortExecutor>(std::move(right_), std::move(sel_cols_right), sm_manager_,
+                                                            context_);
+        }
     }
 
     ColMeta get_col_offset(const TabCol& target) {
@@ -63,7 +89,7 @@ public:
         return *col;
     }
 
-    void print_sorted_results(const std::vector<ColMeta>& cols, std::vector<RmRecord>& recs) {
+    void print_sorted_results(const std::vector<ColMeta>& cols, std::unique_ptr<AbstractExecutor>& executor) {
         std::vector<std::string> captions;
         size_t size = cols.size();
         captions.reserve(size);
@@ -73,11 +99,12 @@ public:
         // print header into file
         SORTED_PRINTER.print_vector(captions);
 
-        for (auto& Tuple : recs) {
+        for (executor->beginTuple(); !executor->is_end(); executor->nextTuple()) {
+            auto Tuple = executor->Next();
             std::vector<std::string> columns;
             for (auto& col : cols) {
                 std::string col_str;
-                char* rec_buf = Tuple.data + col.offset;
+                char* rec_buf = Tuple->data + col.offset;
                 if (col.type == TYPE_INT) {
                     col_str = std::to_string(*(int*)rec_buf);
                 } else if (col.type == TYPE_FLOAT) {
@@ -97,7 +124,7 @@ public:
         int op = 0;
         for (auto& cond : fed_conds_) {
             // 寻找左字段元数据
-            auto left = std::find_if(cols_.begin(), cols_.end(), [&](ColMeta& a) {
+            auto left = std::find_if(cols_.begin(), cols_.end(), [&](const ColMeta& a) {
                 return a.tab_name == cond.lhs_col.tab_name && a.name == cond.lhs_col.col_name;
             });
             ColType ltype = left->type;
@@ -139,136 +166,102 @@ public:
     void goNext() {
         if (isend)
             return;
-        if (++right_it_ != right_end_) {
-            return;
-        } else {
-            right_it_ = right_start_;
-        }
-        if (++left_it_ == left_recs_.end()) {
-            isend = true;
+        if (++right_it_ == right_recs_.end()) {
+            left_->nextTuple();
+            if (left_->is_end()) {
+                isend = true;
+            }
         }
     }
 
     // 仅实现INNER JOIN
     void nextMatch() {
-        if (right_it_ != right_start_) {
-            return;
+        if (has_match && right_it_ != right_recs_.end()) {
+            goNext();
+            // 说明右表相同记录遍历未完成
+            if (right_it_ != right_recs_.end()) {
+                return;
+            }
         }
         while (!isend) {
             std::unique_ptr<RmRecord> rec = std::make_unique<RmRecord>(len_);
+            std::unique_ptr<RmRecord> left_rec = left_->Next();
+            std::unique_ptr<RmRecord> right_rec;
+            // 防止right_已经遍历到结尾
+            if (!has_match) {
+                right_rec = right_->Next();
+            } else {
+                right_rec = std::make_unique<RmRecord>(right_recs_.back());
+            }
             // INNER JOIN
-            memcpy(rec->data, left_it_->data, left_it_->size);
-            memcpy(rec->data + left_it_->size, right_it_->data, right_it_->size);
+            memcpy(rec->data, left_rec->data, left_rec->size);
+            memcpy(rec->data + left_rec->size, right_rec->data, right_rec->size);
 
             int op = getOp(rec);
 
             if (op == -1) {
-                if (++left_it_ == left_recs_.end()) {
+                left_->nextTuple();
+                if (left_->is_end()) {
                     isend = true;
                 }
+                has_match = false;
             } else if (op == 1) {
-                right_it_ = right_end_;
-                if (right_it_ == right_recs_.end()) {
-                    isend = true;
+                if (!has_match) {
+                    right_->nextTuple();
+                    if (right_->is_end()) {
+                        isend = true;
+                    }
+                } else {
+                    has_match = false;
                 }
-                right_start_ = right_it_;
-                right_end_ = right_it_ + 1;
             } else if (op == 0) {
-                // 寻找右表所有重复元组
-                while (right_end_ != right_recs_.end()) {
-                    // INNER JOIN
-                    memcpy(rec->data + left_it_->size, right_end_->data, right_end_->size);
+                // 左表记录与上一个不同
+                if (!has_match) {
+                    right_recs_.clear();
+                    // 寻找右表所有重复元组
+                    while (!right_->is_end()) {
+                        // INNER JOIN
+                        right_rec = right_->Next();
+                        memcpy(rec->data + left_rec->size, right_rec->data, right_rec->size);
 
-                    if (getOp(rec) != 0)
-                        break;
-                    ++right_end_;
+                        if (getOp(rec) != 0)
+                            break;
+                        right_recs_.push_back(*right_rec);
+                        right_->nextTuple();
+                    }
+                    has_match = true;
                 }
+                right_it_ = right_recs_.begin();
                 break;
             }
         }
     }
 
-    // 内排序
-    void internalSort() {
-        std::sort(left_recs_.begin(), left_recs_.end(), [&](const auto& a, const auto& b) -> bool {
-            for (auto& cond : fed_conds_) {
-                if (cond.is_rhs_val)
-                    continue;
-                // 寻找元数据
-                auto it = std::find_if(cols_.begin(), cols_.end(), [&](ColMeta& a) {
-                    return a.tab_name == cond.lhs_col.tab_name && a.name == cond.lhs_col.col_name;
-                });
-                int op = comp_lhs_rhs(it->type, a.data + it->offset, it->type, b.data + it->offset, it->len, it->len);
-                if (op == -1)
-                    return true;
-                if (op == 1)
-                    return false;
-            }
-            return false;
-        });
-        std::sort(right_recs_.begin(), right_recs_.end(), [&](const auto& a, const auto& b) -> bool {
-            for (auto& cond : fed_conds_) {
-                if (cond.is_rhs_val)
-                    continue;
-                // 寻找元数据
-                auto it = std::find_if(cols_.begin(), cols_.end(), [&](ColMeta& a) {
-                    return a.tab_name == cond.rhs_col.tab_name && a.name == cond.rhs_col.col_name;
-                });
-                int op = comp_lhs_rhs(it->type, a.data + it->offset - left_->tupleLen(), it->type,
-                                      b.data + it->offset - left_->tupleLen(), it->len, it->len);
-                if (op == -1)
-                    return true;
-                if (op == 1)
-                    return false;
-            }
-            return false;
-        });
-    }
-
     void beginTuple() override {
+        // 输出排序结果
+        clock_t start = clock();
+        print_sorted_results(right_->cols(), right_);
+        print_sorted_results(left_->cols(), left_);
+        clock_t end = clock();
+        std::cout << "print used: " << (double)(end - start) / CLOCKS_PER_SEC << "s" << std::endl;
+
+        //  初始化
         left_->beginTuple();
         right_->beginTuple();
         isend = left_->is_end() || right_->is_end();
         if (isend)
             return;
 
-        // 如果不输出中间结果,有索引的排序不需要将左右表的所有tuple存储
-        // 读取左右表的所有tuple
-        clock_t start = clock();
-        while (!left_->is_end()) {
-            left_recs_.push_back(*left_->Next());
-            left_->nextTuple();
-        }
-        while (!right_->is_end()) {
-            right_recs_.push_back(*right_->Next());
-            right_->nextTuple();
-        }
-        clock_t end = clock();
-        std::cout << "Scan used: " << (double)(end - start) / CLOCKS_PER_SEC << std::endl;
-
-        start = clock();
-        // 排序
-        if (!is_exist_index_) {
-            internalSort();
-        }
-        end = clock();
-        std::cout << "Sort used: " << (double)(end - start) / CLOCKS_PER_SEC << std::endl;
-
-        left_it_ = left_recs_.begin();
+        right_recs_.clear();
         right_it_ = right_recs_.begin();
-        right_start_ = right_it_;
-        right_end_ = right_it_ + 1;
+        has_match = false;
         // 指向第一个符合条件的Tuple
         nextMatch();
-
-        start = clock();
-        print_sorted_results(right_->cols(), right_recs_);
-        print_sorted_results(left_->cols(), left_recs_);
-        end = clock();
-        std::cout << "Print used: " << (double)(end - start) / CLOCKS_PER_SEC << std::endl;
     }
 
     void nextTuple() override {
+        if (isend)
+            return;
         // 跳过上一个符合条件的Tuple
         // 左表连接右表
         goNext();
@@ -276,10 +269,13 @@ public:
     }
 
     std::unique_ptr<RmRecord> Next() override {
+        if (isend)
+            return nullptr;
         std::unique_ptr<RmRecord> rec = std::make_unique<RmRecord>(len_);
+        std::unique_ptr<RmRecord> left_rec = left_->Next();
         // INNER JOIN
-        memcpy(rec->data, left_it_->data, left_it_->size);
-        memcpy(rec->data + left_it_->size, right_it_->data, right_it_->size);
+        memcpy(rec->data, left_rec->data, left_rec->size);
+        memcpy(rec->data + left_rec->size, right_it_->data, right_it_->size);
         return rec;
     }
 
diff --git a/src/portal.h b/src/portal.h
index 73da27281b5cc7c87b9cdae721668a4179c8c67f..92440bc7500d4509d59f365163477013c5653aa2 100644
--- a/src/portal.h
+++ b/src/portal.h
@@ -210,7 +210,7 @@ public:
                                                                 x->type);
             } else if (plan->tag == T_SortMerge) {
                 join = std::make_unique<SortMergeJoinExecutor>(std::move(left), std::move(right), std::move(x->conds_),
-                                                               x->type, is_exist_index, context);
+                                                               x->type, is_exist_index, sm_manager_, context);
             }
             return join;
         } else if (auto x = std::dynamic_pointer_cast<SortPlan>(plan)) {
diff --git a/src/record/rm_scan.h b/src/record/rm_scan.h
index 0de10aa11582a505fa7c56bd34e87111a3127bb7..8431b1723f4ea2f7612ec84bdca5f68ce9f6e351 100644
--- a/src/record/rm_scan.h
+++ b/src/record/rm_scan.h
@@ -26,4 +26,9 @@ public:
     bool is_end() const override;
 
     Rid rid() const override;
+
+    void setRid(Rid& rid) {
+        rid_.page_no = rid.page_no;
+        rid_.slot_no = rid.slot_no;
+    }
 };
diff --git a/test/test_join.py b/test/test_join.py
index a3cd182fdabd230c852fda0ba41a46221fd83cda..4630b9aaca455a1d6031d22ad67bdaa4eec1c898 100644
--- a/test/test_join.py
+++ b/test/test_join.py
@@ -41,7 +41,7 @@ def main():
         message = 'create table stock (s_i_id int, s_w_id int, s_quantity int, s_dist_01 char(24), s_dist_02 char(24), s_dist_03 char(24), s_dist_04 char(24), s_dist_05 char(24), s_dist_06 char(24), s_dist_07 char(24), s_dist_08 char(24), s_dist_09 char(24), s_dist_10 char(24), s_ytd float, s_order_cnt int, s_remote_cnt int, s_data char(50));'
         send(message)
 
-        n = 10000
+        n = 25000
         candidates = list(range(n))
         rand_idx = random.sample(candidates, n)
 
@@ -57,17 +57,17 @@ def main():
         
         t = []
 
-        message = 'SET enable_nestloop = true;'
-        send(message)
-        message = 'SET enable_sortmerge = false;'
-        send(message)
-        message = 'select * from item, stock where s_i_id = i_id;'
-        start = time.time()
-        send(message)
-        end = time.time()
-        t.append(end - start)
-        # t.append(1)
-        # t.append(1)
+        # message = 'SET enable_nestloop = true;'
+        # send(message)
+        # message = 'SET enable_sortmerge = false;'
+        # send(message)
+        # message = 'select * from item, stock where s_i_id = i_id;'
+        # start = time.time()
+        # send(message)
+        # end = time.time()
+        # t.append(end - start)
+        t.append(1000)
+        # t.append(1000)
 
         message = 'SET enable_nestloop = false;'
         send(message)