- Having, Grouping SQL
- Indexes in DB
- Union and union all difference
- Self join vs outer join
- Cascade : when parent data is updated or deleted, child’s data is also
- Normalization
- Subquery
Category: Interview
Hibernate IQs
- Hibernate Mapping with Multiple column
- How data is stored in Cassandra
- What is difference between Cassandra and RDBMS
- Embedded and embeddable
- N+1 Problem and solution
N+1 Problem
Definition
The N+1 problem is a performance issue that can occur in database-driven applications, particularly those using object-relational mapping (ORM) frameworks like Hibernate, when fetching data using relationships. The problem arises when the application executes N+1 database queries to retrieve N entities along with their associated relationships.
Explanation :
- Explanation:
- Suppose you have an entity
Parentwith a one-to-many relationship toChild. When you fetch a list ofParententities, each with a collection of associatedChildentities, the N+1 problem occurs. - For each
Parententity fetched, an additional query is executed to fetch its associatedChildentities. Hence, if you have NParententities, you end up executing N+1 queries (N queries to fetch theParententities and 1 query for eachParentto fetch itsChildentities).
- Suppose you have an entity
- Example:
- Consider the following code:
List<Parent> parents = entityManager.createQuery("SELECT p FROM Parent p", Parent.class).getResultList();
for (Parent parent : parents) {
// Each iteration triggers an additional query to fetch Child entities for each Parent
List<Child> children = parent.getChildren();
}
In this example, if there are N Parent entities, it leads to N+1 queries.
Solution to N+1 Problem:
- Eager loading (not recommended)
- lazy loading with batch fetching(recommended)
Eager Fetching:
- One solution is to use eager fetching, where the associated entities are fetched along with the main entity in a single query.
- In JPA/Hibernate, you can use the
@OneToManyor@ManyToOneannotation with thefetchattribute set toFetchType.EAGER.
@Entity
public class Parent {
// Other annotations...
@OneToMany(fetch = FetchType.EAGER, mappedBy = "parent")
private List<Child> children;
}
However, eager fetching has its downsides, such as potentially fetching more data than needed and impacting performance in other scenarios.
Lazy Loading with Batch Fetching:
- A more efficient solution is to use lazy loading for relationships and employ batch fetching to minimize the number of queries.
- Lazy loading defers the loading of associated entities until they are actually accessed, and batch fetching allows fetching multiple entities in a single query.
@Entity
public class Parent {
// Other annotations...
@OneToMany(mappedBy = "parent")
private List<Child> children;
}
@Entity
public class Child {
// Other annotations...
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
}
List<Parent> parents = entityManager.createQuery("SELECT p FROM Parent p", Parent.class).getResultList();
// Batch fetch the children for all parents in a single query
parents.forEach(parent -> {
List<Child> children = parent.getChildren(); // Lazy loading
children.size(); // Trigger batch fetch
});
- With this approach, you fetch the children in batches, reducing the number of queries.
It’s essential to carefully choose the fetching strategy based on your application’s requirements and performance considerations to avoid the N+1 problem and ensure efficient database access.
Embedded and embeddable
@Embedded and @Embeddable annotations are used to represent and map composite or embedded objects in database tables. These annotations allow you to model a part of an entity as an embedded object, and the data of this embedded object is stored in the same table as the owning entity.
@Embeddable:
- Annotation:
@Embeddableis used to annotate a class whose instances are intended to be embedded into entities.- It marks a class as embeddable, meaning its instances can be used as components within other entities.
- Example:
- Let’s say you have an
Addressclass that you want to embed in other entities.
- Let’s say you have an
@Embeddable
public class Address {
private String street;
private String city;
private String zipCode;
// Constructors, getters, setters
}
@Embedded:
- Annotation:
@Embeddedis used to embed an@Embeddableobject within an entity.- It is placed on a field or a method in the entity class to indicate that the attribute should be stored as an embedded object in the database.
- Example:
- Consider an
Employeeentity that includes an embeddedAddress.
- Consider an
@Entity
public class Employee {
@Id
@GeneratedValue
private Long id;
private String name;
@Embedded
private Address address;
// Constructors, getters, setters
}
In this example, the Employee entity has an @Embedded attribute, address, which is of type Address. The @Embeddable annotation on the Address class indicates that instances of Address can be embedded within other entities.
With these annotations, when Hibernate generates the database schema, it creates a single table for the Employee entity that includes columns for both the regular attributes of the Employee entity and the attributes of the embedded Address object.
CREATE TABLE Employee (
id BIGINT PRIMARY KEY,
name VARCHAR(255),
address_street VARCHAR(255),
address_city VARCHAR(255),
address_zipCode VARCHAR(255)
);
This way, the data of the embedded object is stored as part of the owning entity’s table, allowing you to model more complex data structures in your domain model.