利用C++實現⾃然連接操作算法
1. 實驗目的
本次實驗三需要完成的內容為實現然連接(natural join)操作算法,對兩個關系進然連接,具體實現基於塊的嵌套循環連接(Block-based Nested Loop Join)算法。
我們要實現的函數在 executer.cpp 文件中。
bool NestedLoopJoinOperator::execute(int numAvailableBufPages, File &resultFile)
2. 實驗內容
首先,我們讀取兩個表頭的信息
TableId leftTableId = catalog->getTableId("r"); TableId rightTableId = catalog->getTableId("s"); badgerdb::File left = File::open(catalog->getTableFilename(leftTableId)); badgerdb::File right = File::open(catalog->getTableFilename(rightTableId));
運用兩層循環尋找兩個表中名稱與類型完全相同的屬性,將他們全部標記出來,用於之後的自然連接操作。
vector<int> leftForeignKeyId; vector<int> rightForeignKeyId; for (int i = 0; i < leftTableSchema.getAttrCount(); i++) { for (int j = 0; j < rightTableSchema.getAttrCount(); j++) { if ((leftTableSchema.getAttrName(i) == rightTableSchema.getAttrName(j)) && (leftTableSchema.getAttrType(i) == rightTableSchema.getAttrType(j))) { leftForeignKeyId.push_back(i); rightForeignKeyId.push_back(j); break; } } }
準備操作做完後,開始進行自然連接操作。
用循環從磁盤中讀取兩個頁面的信息,記錄 io 操作次數
for (badgerdb::FileIterator leftPage = left.begin(); leftPage != left.end(); leftPage++) { badgerdb::Page *bufferedLeftPage; bufMgr->readPage(&left, (*leftPage).page_number(), bufferedLeftPage); numIOs += 1; for (badgerdb::FileIterator rightPage = right.begin(); rightPage != right.end(); rightPage++) { badgerdb::Page *bufferedRightPage; bufMgr->readPage(&right, (*rightPage).page_number(), bufferedRightPage); numIOs += 1;
之後,從表中讀取全部的元組的信息,進行對比。
讀取的元組信息有特殊的格式,並不能直接利用,所以需要先瞭解元組在表中儲存的格式,然後進行解讀。元組的存儲方式可以從 storage.cpp 中的 createTupleFromSQLStatement 函數中得知。
switch (dataType) { // (int) 56 (0011 1000) -> (char) '\0''\0''\0''8' case INT: { // convert int value into 4 byte representation case CHAR: { // (char(5) ) 'abc' -> 'abc00' case VARCHAR: { // (varchar(8) ) 'abc' -> '3''abc' (3 refer to the ascii // code number correspond alpha)
於是,我們根據註釋的存儲方式編寫解析函數,該函數輸入為文件中存儲的元組,輸出為數組表示的直觀的元組內容。
vector<string> analyze(string record, badgerdb::TableSchema schema)
先讀取其中一個表的元組,用塊來存儲。
for (badgerdb::PageIterator leftRecord = bufferedLeftPage->begin(); leftRecord != bufferedLeftPage->end(); leftRecord++) { vector<string> leftInfo = analyze(*leftRecord, leftTableSchema); numUsedBufPages += 1; block.push_back(leftInfo); if (block.size() < BLOCK_SIZE) { continue; }
然後讀取另一個表的元組信息,
for (badgerdb::PageIterator rightRecord = bufferedRightPage->begin(); rightRecord != bufferedRightPage->end(); rightRecord++) { numUsedBufPages += 1;
將兩個元組當中的屬性名相同的屬性列信息進行對比,
bool f = true; for(int i = 0; i < leftForeignKeyId.size(); i++) { if(leftInfo[leftForeignKeyId[i]] != rightInfo[rightForeignKeyId[i]]) { f = false; break; } }
如果全部相同,則代表需要進行自然連接操作。
if(f) { string current_line = "INSERT INTO TEMP_TABLE VALUES (" + leftInfo[0]; for (int i = 1; i < leftTableSchema.getAttrCount(); i++) { current_line = current_line + ", " + leftInfo[i]; } for (int i = 0; i < rightTableSchema.getAttrCount(); i++) { current_line = current_line + ", " + rightInfo[i]; } current_line = current_line + ");"; string tuple = HeapFileManager::createTupleFromSQLStatement(current_line, catalog); numResultTuples += 1; HeapFileManager::insertTuple(tuple, resultFile, bufMgr); }
否則不進行任何操作。
在全部循環都結束之後,塊中可能還會有剩餘的信息沒有進行處理,此時再單獨對剩餘信息進行處理,代碼基本相同。
3. 實驗結果
代碼運行結果如下:
到此這篇關於利用C++實現⾃然連接操作算法的文章就介紹到這瞭,更多相關C++連接操作算法內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- C++中vector操作方式詳解(多種方式)
- C++ vector數組用法及解析
- C++實現LeetCode(22.生成括號)
- C++vector的用法你都知道嘛
- C++ stringstream格式化輸出輸入詳情