使用 gob 序列化到磁盘后检索

Retrieval after serialization to disk using gob

我一直在学习数据库,也想实现一个用于学习目的而不是用于生产。我有一个定义的模式:

type Row struct {
    ID       int32
    Username string
    Email    string
}

现在,目前,我能够以仅附加的方式将这种类型的结构编码到文件中。

//Just to show i use a file for the encoding, it has missing details.

func NewEncoder(db *DB) *gob.Encoder{
    return gob.NewEncoder(db.File)
}

func SerializeRow(r Row, encoder *gob.Encoder, db *DB) {
    err := encoder.Encode(r)
    if err != nil {
        log.Println("encode error:", err)
    }
}

现在,通过简单地使用 gob.decode

解码整个文件来模仿“select”语句相对容易
func DeserializeRow(decoder *gob.Decoder, db *DB){
    var rows Row
    db.File.Seek(0, 0)
    err := decoder.Decode(&rows)
    for err == nil {
        if err != nil {
            log.Println("decode error:", err)
        }
        fmt.Printf("%d %s %s\n", rows.ID, rows.Username, rows.Email)
        err = decoder.Decode(&rows)
    }
}

我当前的问题是,我希望能够根据 ID 检索特定行。我知道 sqlite 使用 4kb 分页,在某种意义上,序列化的行占据一个“页面”,即。 4KB 直到一个页面不能再容纳它们,然后创建另一个。我如何使用 gob 以最简单和惯用的方式模仿这种行为?

看过:I have seen this and

Gob 流可能包含类型定义和解码指令,因此您无法寻找 Gob 流。您只能从头开始阅读,直到找到所需内容为止。

Gob 流完全不适合table 需要跳过元素的数据库存储格式。

您可以创建一个新的编码器并分别序列化每个记录,在这种情况下您可以跳过元素(通过维护一个文件索引来存储哪个记录从哪个位置开始),但这会非常低效和冗余(如所述在 中,速度和存储成本会随着您写入更多相同类型的值而摊销,并且总是创建新的编码器会失去这种收益。

更好的方法是不使用 encoding/gob,而是定义自己的格式。为了有效地支持搜索 (select),您必须在可搜索的列/字段上构建某种索引,否则您仍然需要执行完整的 table 扫描。