1

my user's table in the database is becoming increasingly larger (in terms of columns not rows) and as a consequence is slowing down various areas of my site. This is because it tries to grab every column from the user's table everytime it does a join against it.

I figured i would keep all the common fields in the user's table and then put the additional fields in seperate tables. For example, say i have the following tables in my database:

Users:

- UserID (PK, Identity)
- UserName
- Password
...

UsersActivity:

- UserID (PK, FK)
- LastActivityDate
- LastLoginDate
...

UsersPreferences:

- UserID (PK, FK)
- HtmlEmail
- HideEmail
...

With the following entities:

public class User {
    public virtual int UserID { get; set; }
    public virtual string UserName { get; set; }
    public virtual string Password { get; set; }
    public virtual UserActivity Activity { get; set; }
    public virtual UserPreferences Preferences { get; set; }
}

public class UserActivity {
    public virtual User User { get; set; }
    public virtual DateTime LastActivityDate { get; set; }
    public virtual DateTime LastLoginDate { get; set; }
}

public class UserPreferences {
    public virtual User User { get; set; }
    public virtual bool HtmlEmail { get; set; }
    public virtual bool HideEmail { get; set; }
}

I was just wondering what is the best way to map this for optimum performance? I figured i could do a one-to-one mapping on the Activity and Performance properties in the User entity. However as far as i understand one-to-one mapping doesn't support lazy loading and this approach would end up being slower.

I also looked into component mapping and wasn't too sure whether i could map this into a seperate table (please correct me if it would be better to keep it in the same table) and whether components supported lazy loading.

Before i go about doing some heavy refactoring of my application i thought i would get the opinion of someone who might have done this. Really appreciate the help.

Thanks

Edit: I found that you could lazy load a one-to-one relationship as long as it is required/constrained. Which it is my case. Therefore i went ahead and carried out the instructions in the following article:

http://brunoreis.com/tech/fluent-nhibernate-hasone-how-implement-one-to-one-relationship/

The trouble now is that i get the error:

NHibernate.Id.IdentifierGenerationException: NHibernate.Id.IdentifierGenerationException: null id generated for: UserActivity.

nfplee
  • 7,643
  • 12
  • 63
  • 124
  • I've posted a follow up question which is more specific to mapping a one-to-one relationship which you can find here http://stackoverflow.com/questions/4660160/map-one-to-one-relationship-doesnt-allow-inserting. I'll update this question with my findings in the near future. – nfplee Jan 11 '11 at 16:52

2 Answers2

0

In NHibernate 3.0 one-to-one relationship supports lazy loading.

And I think that it is better to use Component with combination of Lazy property. Then you will be able to leave all properties in one table and not load them all at once.

Sly
  • 15,046
  • 12
  • 60
  • 89
  • I'm not in a position to upgrade to version 3 atm. The component idea is going to be my fallback if i can't get a one-to-one relationship working. I've updated my question with more details on the issues i'm having with one-to-one mapping. I use fluent nhibernate but the equivalent in xml is very similar. – nfplee Jan 11 '11 at 15:40
  • The latest version of NHibernate 3 looks to have addressed the issues i was having and i am now in a position to upgrade. – nfplee May 23 '11 at 10:19
0

You should do some additional application profiling to determine why you're having a performance problem. It's unlikely that it's due to the number of columns in the select list. You probably have an N+1 select problem.

That said, there are many good reasons to use a lightweight object so you might want to look at implementing a DTO (data transfer object) for this.

Community
  • 1
  • 1
Jamie Ide
  • 48,427
  • 16
  • 81
  • 117
  • I've updated my question with more information. It's not a select n + 1 issue. I'm trying to avoid my queries from grabbing every field in a select statement as they're not always needed. – nfplee Jan 11 '11 at 15:42
  • I'm still very skeptical that selecting every field is the root cause of your performance problem. – Jamie Ide Jan 11 '11 at 15:58
  • There's other issues aswell i'm sure but say my users table has 2 fields Biography (text) and MetaDescription (text) which are only displayed on the users profile. There's no need for me to pull back this information everytime i try to access the users table. I could lazy load the property but for each property you get an additional hit on the database. By putting them in their own table it allows me to group these properties together. – nfplee Jan 11 '11 at 16:56
  • 1
    Text fields might make a difference, but I would profile, profile, profile and to make sure that you're addressing the biggest bottleneck first. Assuming that you only need a subset of read-only fields for the user on all but the profile page, I would use a lightweight DTO. It's a much simpler solution than splitting the class. – Jamie Ide Jan 11 '11 at 17:35