Especificación de un índice (clave no única) mediante JPA

98

¿Cómo se define un campo, por ejemplo, emailque tiene un índice utilizando anotaciones JPA? Necesitamos una clave no única emailporque hay literalmente millones de consultas en este campo por día y es un poco lento sin la clave.

@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;
}

He visto una anotación específica de hibernación, pero estoy tratando de evitar soluciones específicas de proveedores, ya que todavía estamos decidiendo entre hibernación y núcleo de datos.

ACTUALIZAR:

A partir de JPA 2.1, puede hacer esto. Ver: La anotación @Index no está permitida para esta ubicación.

Jacob
fuente
6
Sería genial si pudiera actualizar la respuesta para que la gente descubra que con JPA 2.1 realmente hay una manera de hacerlo
borjab
2
¿Por qué no acepta la respuesta más votada?
naXa

Respuestas:

206

Con JPA 2.1 debería poder hacerlo.

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;

} 

Actualización : si alguna vez necesita crear e indexar con dos o más columnas, puede usar comas. Por ejemplo:

@Entity
@Table(name    = "company__activity", 
       indexes = {@Index(name = "i_company_activity", columnList = "activity_id,company_id")})
public class CompanyActivity{
borjab
fuente
Gracias a Alvin por su respuesta. (+1 voto). Pero tuve que buscar algunas cosas y espero que este ejemplo pueda hacer su vida más fácil
borjab
Exactamente lo que estaba buscando, un código simple y limpio recortado, no solo describiendo todo. Gracias +1.
DominikAngerer
2
@borjab: ¿podría darme una pista sobre dónde puedo encontrar un ejemplo o especificación "oficial" para usar la @Indexanotación dentro de la @Tableanotación? Busqué en JSR 338 pero no lo encontré allí. Tu publicación me resulta muy útil.
JimHawkins
2
@Ulrich No es exactamente la documentación oficial, sino el blog de oracle blogs.oracle.com/arungupta/entry/jpa_2_1_schema_generation
borjab
Me pregunto, si tengo una columna con @Column (única = verdadera), ¿se fusiona con la lista de índices (ya que única también es un índice)?
wkrueger
34

Una colección única de anotaciones de índice seleccionadas a mano

= Especificaciones =

= Estructuras ORM =

= ORM para Android =

= Otro (difícil de categorizar) =

  • Realm - Base de datos alternativa para iOS / Android: Anotación io.realm.annotations.Index;
  • Empire-db : una capa de abstracción de base de datos relacional ligera pero potente basada en JDBC. No tiene definición de esquema a través de anotaciones;
  • Kotlin NoSQL (GitHub) : un DSL reactivo y de tipo seguro para trabajar con bases de datos NoSQL (PoC): ???
  • Slick - Mapeo relacional funcional reactivo para Scala. No tiene definición de esquema a través de anotaciones.

Solo ve por uno de ellos.

naXa
fuente
31

¡JPA 2.1 (finalmente) agrega soporte para índices y claves externas! Consulte este blog para obtener más detalles. JPA 2.1 es parte de Java EE 7, que ya está disponible.

Si le gusta vivir al límite, puede obtener la última instantánea de eclipselink desde su repositorio maven (groupId: org.eclipse.persistence, artifactId: eclipselink, versión: 2.5.0-SNAPSHOT). Solo para las anotaciones JPA (que deberían funcionar con cualquier proveedor una vez que sean compatibles con 2.1) use artifactID: javax.persistence, versión: 2.1.0-SNAPSHOT.

Lo estoy usando para un proyecto que no estará terminado hasta después de su lanzamiento, y no he notado ningún problema horrible (aunque no estoy haciendo nada demasiado complejo con él).

ACTUALIZACIÓN (26 de septiembre de 2013): Actualmente, las versiones candidatas de lanzamiento y lanzamiento de eclipselink están disponibles en el repositorio central (principal), por lo que ya no es necesario agregar el repositorio de eclipselink en los proyectos de Maven. La última versión de lanzamiento es 2.5.0 pero también está presente la 2.5.1-RC3. Cambiaría a 2.5.1 lo antes posible debido a problemas con la versión 2.5.0 (las cosas de modelgen no funcionan).

Alvin Thompson
fuente
9

En JPA 2.1 necesitas hacer lo siguiente

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() {
    }
}

En el ejemplo anterior, la tabla TEST_PERSON tendrá 3 índices:

  • índice único en el ID de clave principal

  • índice de EDAD

  • índice compuesto en FNAME, SNAME

Nota 1: Obtiene el índice compuesto al tener dos anotaciones @Index con el mismo nombre

Nota 2: usted especifica el nombre de la columna en la lista de columnas, no el nombre del campo

James Clayton
fuente
5

Realmente me gustaría poder especificar índices de base de datos de una manera estandarizada pero, lamentablemente, esto no es parte de la especificación JPA (tal vez porque la especificación JPA no requiere el soporte de generación DDL, que es una especie de obstáculo para tal característica).

Por lo tanto, tendrá que confiar en una extensión específica del proveedor para eso. Hibernate, OpenJPA y EclipseLink ofrecen claramente tal extensión. No puedo confirmar para DataNucleus, pero dado que la definición de índices es parte de JDO, supongo que sí.

Realmente espero que el soporte de índices se estandarice en las próximas versiones de la especificación y, por lo tanto, de alguna manera no esté de acuerdo con otras respuestas, no veo ninguna buena razón para no incluir tal cosa en JPA (especialmente porque la base de datos no siempre está bajo su control) para un soporte óptimo de generación de DDL.

Por cierto, sugiero descargar la especificación JPA 2.0.

Pascal Thivent
fuente
4

Hasta donde yo sé, no existe una forma cruzada de proveedores de JPA para especificar índices. Sin embargo, siempre puede crearlos a mano directamente en la base de datos, la mayoría de las bases de datos los recogerán automáticamente durante la planificación de consultas.

Tassos Bassoukos
fuente
2
jajaja, eso es asumiendo que tienes DBA que hacen el trabajo de un DBA (:
Jacob
3
Me parece un poco extraño que haya una forma de hacer "único" pero no una forma de hacer un índice.
Jacob
7
@Jacob - Bueno, es importante saber a nivel de aplicación si algún campo será único o no. Los índices, por otro lado, tienen el propósito de optimizar el acceso a la base de datos. No hay necesidad (por lo que veo) de saber si una columna es un índice o no en la capa de Java. Como dijiste, el DBA puede configurar un índice si parece que una columna en particular se beneficiaría de él.
Java Drinker
1
@Jacob, no hay soporte de Index porque eso es simplemente una optimización (generalmente una importante, pero aún así una optimización). OTOH, si un campo (o conjunto de campos) es único o no, depende del modelo y afectará la corrección. Además, no es necesario un DBA completo de 200 USD / Hr, por lo general son suficientes algunas declaraciones simples de creación de índices.
Tassos Bassoukos
8
Especifica JPA 2.1javax.persistence.Index
Lukas Eder
2

EclipseLink proporcionó una anotación (por ejemplo, @Index ) para definir un índice en las columnas. Hay un ejemplo de su uso. Se incluye parte del ejemplo ...

Los campos firstName y lastName están indexados, juntos e individualmente.

@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
fuente
1

OpenJPA le permite especificar una anotación no estándar para definir el índice en la propiedad.

Los detalles están aquí .

experto
fuente
0

No es posible hacer eso usando la anotación JPA. Y esto tiene sentido: cuando UniqueConstraint define claramente las reglas de un negocio, un índice es solo una forma de agilizar la búsqueda. Entonces, esto realmente debería hacerlo un DBA.

Thierry-Dimitri Roy
fuente
0

Esta solución es para EclipseLink 2.5 y funciona (probado):

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

Esto asume un orden ascendente.

Joe Almore
fuente