简体   繁体   中英

Many-to-many on single entity with join table

I have a task that require some "special" users to be able to switch between accounts without the need to login. As a starting point I have a join table that consists only of Users ID-s. In form of PRIMARY_USER_ID, and SECONDARY_USER_ID as a foreign keys from USERS table. The first thing that needs to be implemented is GET of all connections between Users. [{"primary_username", "primary_email","secondary_username","secondary_email"}].

I have created a many-to-many relationship on User entity, where both sides of relationship are on User.

@EqualsAndHashCode.Exclude
@ToString.Exclude
@ManyToMany(fetch = FetchType.LAZY, cascade = {
        CascadeType.PERSIST,
        CascadeType.MERGE
})
@JoinTable(name = "CONTACTS_ONE_LOGIN",
        joinColumns = { @JoinColumn(name = "PRIMARY_CONTACT")},
        inverseJoinColumns = {@JoinColumn(name = "SECONDARY_CONTACT")}
)
private Set<Contact> secondaryContacts = new HashSet<>();

@EqualsAndHashCode.Exclude
@ToString.Exclude
@ManyToMany(cascade = {
        CascadeType.REMOVE
},
        mappedBy = "secondaryContacts")
private Set<Contact> primaryContacts = new HashSet<>();

Now the problem is, when i want to get all connections between contacts, I would need to get first all the information from the join table, and then go through each PRIMARY_CONTACT_ID to get it's connected contacts. Which would result in very low performances.

I wanted to change this to have an CONNECTED_USERS entity, which would have instead of two USER ID-s have two Many-to-one relationships on USER.

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PRIMARY_CONTACT_ID")
private Contact contact;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "SECONDARY_CONTACT_ID")
private Contact contact;

My question is, is this going to add performance, since in my dev DB i do not have a lot of users to test it properly? Or is there any better way to do this?

It's even harder for us to guess how well your model will perform as we know nothing about your application, its data or its business rules. From your question it seems that only a few users are affected by this requirement. So unless your total user population is in the hundreds of thousands you probably don't need to worry.

Either way it's unlikely the performance benefits of the separate intersection table you propose will justify the overhead of maintaining it. What I do suggest is you build a compound function based index something like this (caveat: right now I have no access to a database so the following is untested and may contain syntax error):

create index connected_users_fbi on your_table (
    case when secondary_contact_id is not null then primary_contact_id end,
     secondary_contact_id);

This index will be useful for identifying primary contacts with secondary contacts. It may also support finding all the primary contacts which are connected to a secondary contact (if you need that feature) through Index Skip Scan.

Obviously don't take my word for it but try to benchmark it with realistic volumes of data. Your project should have a performance environment where you can do such tests. If it doesn't then it's pretty much doomed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM