How many indexes should be created for faster queries - mysql

My object model is given below and would like your inputs on the number of indexes to create for faster query responses (on h2, mysql). Assumptions and questions are given below the following model.
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false, insertable = false, updatable = false)
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#ForeignKey(name = "fk_user_org_id")
#Index(name = "idx_user_org_id")
#JoinColumn(name = "org_id", nullable = false, referencedColumnName = "id")
#NotNull
private Organization organization;
#ManyToOne(fetch = FetchType.LAZY)
#ForeignKey(name = "fk_user_year_id")
#Index(name = "idx_user_year_id")
#JoinColumn(name = "year", nullable = false, referencedColumnName = "id")
#NotNull
private Year year;
#ManyToOne(fetch = FetchType.LAZY)
#ForeignKey(name = "fk_user_created_by")
#Index(name = "idx_user_created_by")
#JoinColumn(name = "created_by", nullable = false, referencedColumnName = "id")
#NotNull
private User createdBy;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "desc")
private String desc;
#Column(name = "is_system", length = LEN_1)
#Type(type = "org.hibernate.type.YesNoType")
private boolean isSystem = false;
#Column(name = "user_type", nullable = false)
private UserType userType;
#Column(name = "status", nullable = false)
#NotNull
private Status status;
}
Our plan is to use multi column indexes instead of a single column index (i.e. create index user_idx based on (organization, year, isSystem, status, userType, createdBy)). Assuming I have this index, will I get optimized responses for my queries listed below.
select * from user where organization=1 and year=2010;
select * from user where organization=1 and year=2010 and isSytem=true or false; (i.e. system users or application defined users)
select * from user where organization=1 and year=2010 and isSytem=false and userType=Manager (i.e. all managers)
select * from user where organization=1 and year=2010 and isSytem=false and userType=Employee (i.e. all employees)
select * from user where organization=1 and year=2010 and isSytem=false and userType=Manager and status=ACTIVE (i.e. Active users)
select * from user where organization=1 and year=2010 and createdBy='Sam' or 'Joe'
Does [6] need a different multi column index, consisting of the above 3 columns?
Since we are creating a multi column index as per my original assumption, can I safely remove the individual indexes (idx_user_org_id, idx_user_year_id, idx_user_created_by) as currently defined in the model?

You should switch the order of the columns in your index:
(organization, year, isSystem, userType, status, createdBy)
This allows it to better serve these two queries:
select * from user where organization=1 and year=2010 and isSystem=false and userType=Manager
select * from user where organization=1 and year=2010 and isSystem=false and userType=Employee
Does [6] need a different multi column index, consisting of the above 3 columns?
It doesn't need a new index - it can use the existing one but in a less efficient way - only the first two columns will be used. Adding a new index for this query looks like a good idea though.
can I safely remove the individual indexes
Yes. You should remove unused indexes otherwise they will just take up disk space and slow down table modifications without providing any benefit.

Related

Placing indexes on a MySQL table using JPA/Hibernate

I would like to set indexes on multiple columns within a single table in MySQL database. After reading this article, I'm not 100% sure which approach to use.
So my (simplified) table looks like this:
#Data
#Entity
#SuperBuilder
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "loan")
public class Loan {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "loan_id", unique = true, nullable = false)
private long id;
#Column(name = "amount", unique = false, nullable = false)
private double amount;
#Column(name = "rate", unique = false, nullable = false)
private double rate;
#Column(name = "payments", unique = false, nullable = false)
private int payments;
#Column(name = "pmt", unique = false, nullable = false)
private double pmt;
}
I will have a lot of search queries, for instance:
SELECT *
FROM Loan loan
WHERE loan.amount =: amount
AND loan.rate =: rate
AND loan.payments =: payments
AND loan.pmt =: pmt
LIMIT 1;
Now, I would like to index fields in WHERE clause. Essentially, I would like to achieve effect of a "composite key" where in table loan there are only unique combinations of mentioned fields. So I cannot have two rows all with some values.
Is there such a configuration?
ou can add a UNIQUE constraint, which would be indexed automatocally
#Table(uniqueConstraints =
{
#UniqueConstraint(name = "UniqueWhereclause", columnNames = { "amount", "rate","payments","pmt" })})
or you can create an index alone
#Entity
#SuperBuilder
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "loan", indexes = {
#Index(columnList = "amount, rate,payments,pmt", name = "name_idx") })
DOUBLE is likely to cause trouble for you. Switch to DECIMAL with a suitable number of decimal places -- so that = can be tested correctly.
Also, that's a strange combination of 4 things to use in the WHERE. Any 3 of those columns should (mathematically) determine the value for the 4th.
Does the table also have the name of the person taking out the loan? Or is this table a list of possible loans? As rates change, so you add more rows to the table? But why have the table if 3 columns can be used to compute the 4th?

Getting a list of columns by a list of identifiers

There is a Product entity.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false, unique = true)
private Long id;
#Column(name = "url_img1", nullable = false, length = 50)
private String urlImg1;
Product has an ID field and a urlImg field.
There is a list of Product identifiers.
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(2L);
How can I get all urlImgs of these identifiers using JPA request?
#Query()
List<String> ();
By using a basic query like this select p.urlImg1 from Product p where p.id in :productIds

how can I create a Single Entity from two other tables/Entity JPA hibernate making a INNER JOIN result with a common key

How can I create a Single Entity from two other tables/Entity in JPA/hibernate making a INNER JOIN result with a common key. I was using the below code but it gives me a full join instead of an inner join. it give me records from the meal table even if the
"id 1" does not exist in the allergies table, example:
{id=1, name='tacos', description='Mexican food', price ='10',peanuts=null, celery=null, sesameSeeds=null}
How can constrain to don't return any records if the 'id' is missing from the secondary table allergies? to show only records when the primary key is present in both tables.
I want something like this instead:
{id=1, name='tacos', description='Mexican food', price ='10',peanuts='no', celery='no', sesameSeeds='no'}
Please advise.
#Entity
#Table(name = "meal")
#SecondaryTable(name = "allergens", pkJoinColumns = #PrimaryKeyJoinColumn(name = "meal_id"))
class Meal {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
Long id;
#Column(name = "name")
String name;
#Column(name = "description")
String description;
#Column(name = "price")
BigDecimal price;
#Column(name = "peanuts", table = "allergens")
boolean peanuts;
#Column(name = "celery", table = "allergens")
boolean celery;
#Column(name = "sesame_seeds", table = "allergens")
boolean sesameSeeds;
// standard getters and setters
}

Get children for any level in tree structure but without theirs children using Hibernate?

I have a Folder entity in Hibernate, like so:
#Entity
#Table(name = "folders")
public class Folder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "folder_id", unique = true, nullable = false)
private int id;
#NonNull
#Column(name = "name", length = 100, unique = true, nullable = false)
private String name;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "parent", orphanRemoval = true)
#Column(name = "sub_folders")
private Set<Folder> childFolders = new HashSet<>();
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JsonIgnore
#JoinColumn(name = "parent", referencedColumnName = "folder_id", nullable = true)
private Folder parent;
public Folder() {
}
}
I'm trying to write a finder method or custom query which will do what I wrote in the subject.
So if I send a request going like folders/{parent_folder_id}, let's say value being 1, I should get objects 4 and 5, but without their children, so not including 6,7,8 and 9.
Ideally, hibernate query would be preferred. If not, any sql language is also fine. I'll try to tumble it up to hibernate.
This is what I got, I still get children...
#Query(value = "Select * from folders f where f.parent = ?1 ", nativeQuery = true)
Set<Folder> getFolders(int folder_id);
I think this should work:
make the default fetchtype lazy:
#OneToMany(fetch = FetchType.EAGER, mappedBy = "parent", orphanRemoval = true)
#Column(name = "sub_folders")
private Set<Folder> childFolders = new HashSet<>();
Use a JOIN FETCH in order to eagerly fetch the relationships you want.
SELECT f FROM folders f JOIN FETCH f.childFolders
You probably can achieve something similar with entity graphs but I'm not sure about their interaction with queries.
I got what I need with following query:
#Query(value = "Select folder_id, name, parent From folders f Where f.parent = ?1", nativeQuery = true)
This will give me just name of the folder and its Id.

Hibernate HQL query get data from table associated with another table

I have an entity called Locality as:-
#Entity
#Table(name = "CMN_LOCALITY_MASTER")
public class Locality {
#Id
#Column(name = "LOCALITY_ID", unique = true, nullable = false,length = 11)
#GeneratedValue(strategy = GenerationType.IDENTITY)
int localityId;
#Column(name = "LOCALITY_DESCRIPTION",length=70)
String localityDescription;
#JsonProperty(access = Access.WRITE_ONLY)
#ManyToOne
#JoinColumn(name = "PINCODE_ID")
Pincode pinCode;
#JsonIgnore
#ManyToOne
City city;
}
which contains another entity called City and Pincode.
City is as below:-
#Entity
#Table(name = "CMN_CITY_MASTER")
public class City{
#Id
#Column(name = "CITY_ID", unique = true, nullable = false,length = 11)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int cityId;
#Column(name = "CITY",length = 150)
private String description;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "STATE_ID")
private State state;
}
I want to Get all data from Locality entity/table which has City ID = (e.g. 1)
I tried below queries:-
#Query("SELECT a FROM Locality a INNER JOIN a.city c WHERE c.cityId=?1")
List<Locality>getAllLocalityByCity(int cityId);
and also
#Query("SELECT a FROM Locality a WHERE a.city.cityId=?1")
List<Locality>getAllLocalityByCity(int cityId);
But these are not working.
Could you please suggest me something/way to query the data?
Also, is there an Eclipse Plug-In/Tool to test HQL queries in a faster way than restarting the server for every change in the query?
Could you also suggest reading documents/book for learning HQL?
Since you are not providing any logs or explanation I can suggest you try the following:
#Query("SELECT a FROM Locality a INNER JOIN a.city c WHERE c.cityId = :cityId")
List<Locality>getAllLocalityByCity(#Param("cityId") int cityId);
For learning the HQL I would start with Hibernate Docs. You can take a look at Criteria API as well.