Spécification d'un index (clé non unique) à l'aide de JPA

98

Comment définir un champ, par exemple emailcomme ayant un index utilisant des annotations JPA. Nous avons besoin d'une clé non unique emailcar il y a littéralement des millions de requêtes sur ce champ par jour, et c'est un peu lent sans la clé.

@Entity
@Table(name="person", 
       uniqueConstraints=@UniqueConstraint(columnNames={"code", "uid"}))
public class Person {
    // Unique on code and uid
    public String code;
    public String uid;

    public String username;
    public String name;
    public String email;
}

J'ai vu une annotation spécifique à l'hibernation, mais j'essaie d'éviter les solutions spécifiques au fournisseur car nous sommes toujours en train de décider entre l'hibernation et le datanucleus.

METTRE À JOUR:

Depuis JPA 2.1, vous pouvez le faire. Voir: l'annotation @Index n'est pas autorisée pour cet emplacement

Jacob
la source
6
Je serais bien si vous pouviez mettre à jour la réponse pour que les gens trouvent qu'avec JPA 2.1, il existe vraiment un moyen de le faire
borjab
2
Pourquoi n'acceptez-vous pas la réponse la plus votée?
naXa

Réponses:

206

Avec JPA 2.1, vous devriez pouvoir le faire.

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Index;
import javax.persistence.Table;

@Entity
@Table(name = "region",
       indexes = {@Index(name = "my_index_name",  columnList="iso_code", unique = true),
                  @Index(name = "my_index_name2", columnList="name",     unique = false)})
public class Region{

    @Column(name = "iso_code", nullable = false)
    private String isoCode;

    @Column(name = "name", nullable = false)
    private String name;

} 

Mise à jour : Si jamais vous avez besoin de créer et d'indexer avec deux colonnes ou plus, vous pouvez utiliser des virgules. Par exemple:

@Entity
@Table(name    = "company__activity", 
       indexes = {@Index(name = "i_company_activity", columnList = "activity_id,company_id")})
public class CompanyActivity{
Borjab
la source
Merci à Alvin pour sa réponse. (+1 vote). Mais j'ai dû chercher quelques trucs et j'espère que cet exemple vous facilitera la vie
borjab
Exactement ce que je cherchais - un code simple et propre coupé - ne décrivant pas seulement le tout. Merci +1.
DominikAngerer
2
@borjab - pouvez-vous s'il vous plaît me donner un indice où je peux trouver un exemple "officiel" ou une spécification pour utiliser l' @Indexannotation dans l' @Tableannotation? J'ai cherché sur JSR 338 mais je ne l'ai pas trouvé. Votre message m'est très utile.
JimHawkins
2
@Ulrich Pas exactement la documentatio officielle mais le blog oracle blogs.oracle.com/arungupta/entry/jpa_2_1_schema_generation
borjab
Je me demande, si j'ai une colonne avec @Column (unique = true), est-elle fusionnée avec la liste des index (car unique est également un index)?
wkrueger
34

Une collection unique d'annotations d'index triées sur le volet

= Spécifications =

= Cadres ORM =

= ORM pour Android =

= Autre (difficile à catégoriser) =

  • Realm - Alternative DB pour iOS / Android: Annotationio.realm.annotations.Index ;
  • Empire-db - une couche d'abstraction DB relationnelle légère mais puissante basée sur JDBC. Il n'a pas de définition de schéma via des annotations;
  • Kotlin NoSQL (GitHub) - un DSL réactif et de type sécurisé pour travailler avec les bases de données NoSQL (PoC): ???
  • Slick - Cartographie relationnelle fonctionnelle réactive pour Scala. Il n'a pas de définition de schéma via des annotations.

Optez pour l'un d'entre eux.

naXa
la source
31

JPA 2.1 (enfin) ajoute le support des index et des clés étrangères! Consultez ce blog pour plus de détails. JPA 2.1 fait partie de Java EE 7, qui est sorti.

Si vous aimez vivre à la périphérie, vous pouvez obtenir le dernier instantané pour eclipselink à partir de leur référentiel maven (groupId: org.eclipse.persistence, artifactId: eclipselink, version: 2.5.0-SNAPSHOT). Pour les annotations JPA uniquement (qui devraient fonctionner avec n'importe quel fournisseur une fois qu'elles prennent en charge la version 2.1), utilisez artifactID: javax.persistence, version: 2.1.0-SNAPSHOT.

Je l'utilise pour un projet qui ne sera terminé qu'après sa sortie, et je n'ai remarqué aucun problème horrible (bien que je ne fasse rien de trop complexe avec lui).

MISE À JOUR (26 septembre 2013): Aujourd'hui, les versions et versions candidates d'eclipselink sont disponibles dans le référentiel central (principal), vous n'avez donc plus à ajouter le référentiel eclipselink dans les projets Maven. La dernière version est la 2.5.0 mais 2.5.1-RC3 est également présente. Je passerais à 2.5.1 dès que possible en raison de problèmes avec la version 2.5.0 (le truc modelgen ne fonctionne pas).

Alvin Thompson
la source
9

Dans JPA 2.1, vous devez effectuer les opérations suivantes

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;

@Entity(name="TEST_PERSON")
@Table(
    name="TEST_PERSON", 
    indexes = {
       @Index(name = "PERSON_INDX_0", columnList = "age"),
       @Index(name = "PERSON_INDX_1", columnList = "fName"),
       @Index(name = "PERSON_INDX_1", columnList = "sName")  })
public class TestPerson {

    @Column(name = "age", nullable = false)
    private int age;

    @Column(name = "fName", nullable = false)
    private String firstName;

    @Column(name = "sName", nullable = false)
    private String secondName;

    @Id
    private long id;

    public TestPerson() {
    }
}

Dans l'exemple ci-dessus, la table TEST_PERSON aura 3 index:

  • index unique sur l'ID de clé primaire

  • index sur AGE

  • index composé sur FNAME, SNAME

Remarque 1: vous obtenez l'index composé en ayant deux annotations @Index avec le même nom

Remarque 2: vous spécifiez le nom de la colonne dans la columnList et non dans le champ fieldName

James Clayton
la source
5

J'aimerais vraiment pouvoir spécifier des index de base de données de manière standardisée mais, malheureusement, cela ne fait pas partie de la spécification JPA (peut-être parce que la prise en charge de la génération DDL n'est pas requise par la spécification JPA, qui est une sorte de barrage pour une telle caractéristique).

Vous devrez donc vous fier à une extension spécifique au fournisseur pour cela. Hibernate, OpenJPA et EclipseLink proposent clairement une telle extension. Je ne peux pas confirmer pour DataNucleus mais comme la définition des index fait partie de JDO, je suppose que c'est le cas.

J'espère vraiment que le support des index sera standardisé dans les prochaines versions de la spécification et donc en quelque sorte en désaccord avec les autres réponses, je ne vois aucune bonne raison de ne pas inclure une telle chose dans JPA (d'autant plus que la base de données n'est pas toujours sous votre contrôle) pour une prise en charge optimale de la génération DDL.

Au fait, je suggère de télécharger la spécification JPA 2.0.

Pascal Thivent
la source
4

Autant que je sache, il n'y a pas de moyen entre les fournisseurs JPA de spécifier des index. Cependant, vous pouvez toujours les créer à la main directement dans la base de données, la plupart des bases de données les récupèrent automatiquement lors de la planification des requêtes.

Tassos Bassoukos
la source
2
lol, c'est en supposant que vous avez des DBA qui font le travail d'un DBA (:
Jacob
3
Je trouve un peu étrange qu'il existe un moyen de faire "unique" mais pas un moyen de faire un index.
Jacob
7
@Jacob - Eh bien, il est important de savoir au niveau de l'application si certains champs seront uniques ou non. Les index, quant à eux, sont destinés à optimiser l'accès à la base de données. Il n'est pas nécessaire (pour autant que je sache) de savoir si une colonne est un index ou non au niveau de la couche java. Comme vous l'avez dit, le DBA peut mettre en place un index s'il semble qu'une colonne particulière en bénéficierait.
Java Drinker
1
@Jacob, il n'y a pas de support d'index car c'est simplement une optimisation (généralement importante, mais toujours une optimisation). OTOH si un champ (ou un ensemble de champs) est unique ou non dépend du modèle et affectera l'exactitude. De plus, pas besoin d'un DBA à part entière de 200 USD / Hr, quelques instructions simples de création d'index suffisent généralement.
Tassos Bassoukos
8
JPA 2.1 spécifiejavax.persistence.Index
Lukas Eder
2

EclipseLink a fourni une annotation (par exemple @Index ) pour définir un index sur les colonnes. Il y a un exemple de son utilisation. Une partie de l'exemple est incluse ...

Les champs firstName et lastName sont indexés, ensemble et individuellement.

@Entity
@Index(name="EMP_NAME_INDEX", columnNames={"F_NAME","L_NAME"})  // Columns indexed together
public class Employee{
    @Id
    private long id;

    @Index                      // F_NAME column indexed
    @Column(name="F_NAME")
    private String firstName;

    @Index                      // L_NAME column indexed
    @Column(name="L_NAME")
    private String lastName;
    ...
}
Nathan
la source
1

OpenJPA vous permet de spécifier une annotation non standard pour définir l'index sur la propriété.

Les détails sont ici .

expert
la source
0

Il n'est pas possible de faire cela en utilisant l'annotation JPA. Et cela a du sens: lorsqu'une UniqueConstraint définit clairement des règles métier, un index n'est qu'un moyen d'accélérer la recherche. Donc, cela devrait vraiment être fait par un DBA.

Thierry-Dimitri Roy
la source
0

Cette solution est pour EclipseLink 2.5 et fonctionne (testé):

@Table(indexes = {@Index(columnList="mycol1"), @Index(columnList="mycol2")})
@Entity
public class myclass implements Serializable{
      private String mycol1;
      private String mycol2;
}

Cela suppose un ordre ascendant.

Joe Almore
la source