3

我正在开发一个小型应用程序,它将存储有关用户、帐户和交易的信息。用户将拥有许多帐户(可能少于 10 个)并且这些帐户将有许多交易(可能有 1000 个)。阅读文档似乎表明嵌入如下是要走的路...

{
"username": "joe",
"accounts": [
    {
        "name": "account1",
        "transactions": [
            {
                "date": "2013-08-06",
                "desc": "transaction1",
                "amount": "123.45"
            },
            {
                "date": "2013-08-07",
                "desc": "transaction2",
                "amount": "123.45"
            },
            {
                "date": "2013-08-08",
                "desc": "transaction3",
                "amount": "123.45"
            }
        ]
    },
    {
        "name": "account2",
        "transactions": [
            {
                "date": "2013-08-06",
                "desc": "transaction1",
                "amount": "123.45"
            },
            {
                "date": "2013-08-07",
                "desc": "transaction2",
                "amount": "123.45"
            },
            {
                "date": "2013-08-08",
                "desc": "transaction3",
                "amount": "123.45"
            }
        ]
    }
 ]
}

我的问题是......由于文档中的事务列表可能会增长到 1000 个,因此数据会变得碎片化并降低性能。我最好有一个文档来存储用户和不会增长得那么大的帐户,然后有一个单独的集合来存储引用到帐户的交易。或者,还有更好的方法?

4

4 回答 4

6

这不是要走的路。你有很多交易,你不知道你会得到多少。而不是这个,你应该像这样存储它们:

{
    "username": "joe",
    "name": "account1",
    "date": "2013-08-06",
    "desc": "transaction1",
    "amount": "123.45"
},
{
    "username": "joe",
    "name": "account1",
    "date": "2013-08-07",
    "desc": "transaction2",
    "amount": "123.45"
},
{
    "username": "joe",
    "name": "account1",
    "date": "2013-08-08",
    "desc": "transaction3",
    "amount": "123.45"
},
{
    "username": "joe",
    "name": "account2",
    "date": "2013-08-06",
    "desc": "transaction1",
    "amount": "123.45"
},
{
    "username": "joe",
    "name": "account2",
    "date": "2013-08-07",
    "desc": "transaction2",
    "amount": "123.45"
},
{
    "username": "joe",
    "name": "account2",
    "date": "2013-08-08",
    "desc": "transaction3",
    "amount": "123.45"
}

在像 MongoDB 这样的 NoSQL 数据库中,你不应该害怕去规范化。正如你所注意到的,我什至没有为用户单独收集而烦恼。如果您的用户有更多信息需要您在每笔交易中显示,您可能还需要考虑包含该信息。

如果您需要搜索或选择这些字段中的任何一个,请不要忘记创建索引,例如:

// look up all transactions for an account
db.transactions.ensureIndex( { username: 1, name: 1 } ); 

和:

// look up all transactions for "2013-08-06"
db.transactions.ensureIndex( { date: 1 } ); 

等等

复制数据有很多好处。使用像上面这样的模式,您可以拥有尽可能多的事务,并且您将永远不会得到任何碎片,因为文档永远不会改变 - 您只会添加它们。这也提高了写入性能,也使执行其他查询变得更加容易。

选择

另一种方法可能是将用户名/名称存储在集合中,并且仅将其 ID 用于交易:

账户:

{
    "username": "joe",
    "name": "account1",
    "account_id": 42,
}

交易:

{
    "account_id": 42,
    "date": "2013-08-06",
    "desc": "transaction1",
    "amount": "123.45"
},

这会创建更小的交易文档,但这确实意味着您必须进行两次查询才能获取用户信息。

于 2013-08-06T13:40:43.947 回答
1

由于文档中的事务列表可能会增长到 1000 个,因此数据会变得碎片化并降低性能。

几乎可以肯定,事实上,如果一个账户的交易在几年内只达到数千而不是数十万,我会感到惊讶。

添加了随着时间的推移,您将从持续增长的文档中看到的碎片级别,如果没有用完根文档空间(它是 16meg),您最终可能会遇到严重的问题。事实上,考虑到您将一个人的所有帐户存储在一个文档下这一事实,我会说您冒着在大约 2 年的时间里填写文档的高风险。

我会参考这种关系。

于 2013-08-06T13:31:42.360 回答
1

我会将交易分开到不同的集合中。似乎用户和事务之间的数据和更新模式完全不同。如果事务不断地添加到用户并导致它一直在增长,它将在 mongo 文件中移动很多。所以是的,它带来了性能影响(碎片化、更多 IO、mongo 的更多工作)。此外,数组操作性能有时会在文档中的大数组上分离,因此在数组中保存 1000 个对象可能不是一个好主意(取决于你用它做什么)。

于 2013-08-06T13:37:32.503 回答
0

您应该考虑使用 ensureIndex() 函数创建索引,它应该会降低性能问题的风险。越早添加这些,您就越能理解集合的结构。我使用 mongo 的时间不长,但我没有遇到任何数据碎片化的问题(反正还没有)

编辑如果您打算将其用于多对象提交,mongo 不支持回滚。您需要使用 64 位版本来允许日志记录并使事务持久化。

于 2013-08-06T13:30:38.057 回答