利用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!

推薦閱讀: