对象关系映射:实现getter的最佳方法是什么?

时间:2021-07-16 16:54:23

What should happen when I call $user->get_email_address()?

Option 1: Pull the email address from the database on demand

public function get_email_address() {
    if (!$this->email_address) {
        $this->read_from_database('email_address');
    }
    return $this->email_address;
}

Option 2: Pull the email address (and the other User attributes) from the database on object creation

public function __construct(..., $id = 0) {
    if ($id) {
        $this->load_all_data_from_db($id);
    }
}

public function get_email_address() {
    return $this->email_address;
}

My basic question is whether it's best to minimize the number of database queries, or whether it's best to minimize the amount of data that gets transferred from the database.

我的基本问题是,最好是最小化数据库查询的数量,或者最好是最小化从数据库传输的数据量。

Another possibility is that it's best to load the attributes that you'll need the most / contain the least data at object creation and everything else on demand.

另一种可能性是,最好加载您最需要的属性/在创建对象时包含最少的数据以及其他所有需要的属性。

A follow-up question: What do ORM abstraction frameworks like Activerecord do?

一个后续问题:像Activerecord这样的ORM抽象框架有什么作用?

3 个解决方案

#1


9  

There really isn't a correct answer for this. Depends on how many users you're loading at once, how many text/blob fields are in your User table, whether your user table loads any associated child objects. As aaronjensen says, this pattern is called lazy loading - and the opposite behaviour (loading everything up front just in case you need it) is known as eager loading.

对此确实没有正确的答案。取决于您一次加载多少用户,您的用户表中有多少文本/ blob字段,无论您的用户表是否加载任何关联的子对象。正如aaronjensen所说,这种模式称为延迟加载 - 相反的行为(在你需要的时候加载所有内容)被称为急切加载。

That said, there is a third option you might want to consider, which is lazy-loading the entire User object when any of its properties are accessed:

也就是说,您可能需要考虑第三个选项,即在访问其任何属性时延迟加载整个User对象:

public function get_email_address() {
    if (!$this->email_address) {
        $this->load_all_data_from_db($this->id)
    }
    return $this->email_address;
}

Advantages of this approach are that you can create a collection of users (e.g. a list of all users whose passwords are blank, maybe?) based on their IDs only, without the memory hit of fully loading every single user, but then you only require a single database call for each user to populate the rest of the user fields.

这种方法的优点是你可以根据他们的ID创建一组用户(例如,密码为空的所有用户的列表?),而没有完全加载每个用户的内存,但是你只需要每个用户填充其余用户字段的单个数据库调用。

#2


6  

Minimize the number of queries. The optimal # of queries is 0, but if you must query because it's not cached, it's 1. Querying for every property is a sure fire way to a system that will never scale, has massive contention issues, and will cause way more headaches than its worth.

最小化查询数量。最佳的查询数为0,但是如果你必须进行查询,因为它没有被缓存,那就是1.查询每个属性对于一个永远不会扩展的系统来说是一种可靠的方法,会产生大量的争用问题,并且会导致比这是值得的。

I should mention that there is value to lazy loading (which is what you're talking about in step 1) if it's unlikely that you will need the data being lazily loaded. If you can though, it's best to be explicit, and fetch exactly or nearly exactly what you need. The less time you spend querying, the less time your connection is open and the more scalable your system is.

我应该提一下,如果您不太可能需要延迟加载数据,那么延迟加载(这是您在步骤1中讨论的内容)是有价值的。如果可以的话,最好是明确的,并准确或几乎完全取得你需要的东西。查询花费的时间越少,连接打开的时间就越短,系统的可扩展性就越高。

#3


0  

I would agree with aaronjensen, except when the amount of data you are pulling is to so great that you'll start to use up an excessive amount of memory. I'm thinking where a row has 3 text fields that are all quite large and all you want is the ID field.

我同意aaronjensen的意见,除非您提取的数据量非常大,以至于您将开始耗尽过多的内存。我在想一行有3个文本字段都非常大,你想要的只是ID字段。

#1


9  

There really isn't a correct answer for this. Depends on how many users you're loading at once, how many text/blob fields are in your User table, whether your user table loads any associated child objects. As aaronjensen says, this pattern is called lazy loading - and the opposite behaviour (loading everything up front just in case you need it) is known as eager loading.

对此确实没有正确的答案。取决于您一次加载多少用户,您的用户表中有多少文本/ blob字段,无论您的用户表是否加载任何关联的子对象。正如aaronjensen所说,这种模式称为延迟加载 - 相反的行为(在你需要的时候加载所有内容)被称为急切加载。

That said, there is a third option you might want to consider, which is lazy-loading the entire User object when any of its properties are accessed:

也就是说,您可能需要考虑第三个选项,即在访问其任何属性时延迟加载整个User对象:

public function get_email_address() {
    if (!$this->email_address) {
        $this->load_all_data_from_db($this->id)
    }
    return $this->email_address;
}

Advantages of this approach are that you can create a collection of users (e.g. a list of all users whose passwords are blank, maybe?) based on their IDs only, without the memory hit of fully loading every single user, but then you only require a single database call for each user to populate the rest of the user fields.

这种方法的优点是你可以根据他们的ID创建一组用户(例如,密码为空的所有用户的列表?),而没有完全加载每个用户的内存,但是你只需要每个用户填充其余用户字段的单个数据库调用。

#2


6  

Minimize the number of queries. The optimal # of queries is 0, but if you must query because it's not cached, it's 1. Querying for every property is a sure fire way to a system that will never scale, has massive contention issues, and will cause way more headaches than its worth.

最小化查询数量。最佳的查询数为0,但是如果你必须进行查询,因为它没有被缓存,那就是1.查询每个属性对于一个永远不会扩展的系统来说是一种可靠的方法,会产生大量的争用问题,并且会导致比这是值得的。

I should mention that there is value to lazy loading (which is what you're talking about in step 1) if it's unlikely that you will need the data being lazily loaded. If you can though, it's best to be explicit, and fetch exactly or nearly exactly what you need. The less time you spend querying, the less time your connection is open and the more scalable your system is.

我应该提一下,如果您不太可能需要延迟加载数据,那么延迟加载(这是您在步骤1中讨论的内容)是有价值的。如果可以的话,最好是明确的,并准确或几乎完全取得你需要的东西。查询花费的时间越少,连接打开的时间就越短,系统的可扩展性就越高。

#3


0  

I would agree with aaronjensen, except when the amount of data you are pulling is to so great that you'll start to use up an excessive amount of memory. I'm thinking where a row has 3 text fields that are all quite large and all you want is the ID field.

我同意aaronjensen的意见,除非您提取的数据量非常大,以至于您将开始耗尽过多的内存。我在想一行有3个文本字段都非常大,你想要的只是ID字段。