Especificando um índice (chave não exclusiva) usando JPA

98

Como você define um campo, por exemplo, emailcomo tendo um índice usando anotações JPA. Precisamos de uma chave não exclusiva ativada emailporque existem literalmente milhões de consultas neste campo por dia, e é um pouco lento sem a chave.

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

Eu vi uma anotação específica de hibernação, mas estou tentando evitar soluções específicas de fornecedores, pois ainda estamos decidindo entre hibernar e datanucleus.

ATUALIZAR:

A partir do JPA 2.1, você pode fazer isso. Veja: A anotação @Index não é permitida para este local

Jacob
fonte
6
Eu seria ótimo se você pudesse atualizar a resposta para que as pessoas descobrissem que com o JPA 2.1 realmente há uma maneira de fazer isso
borjab
2
Por que você não aceita a resposta mais votada?
naXa de

Respostas:

206

Com JPA 2.1, você deve ser capaz de fazer isso.

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;

} 

Atualizar : Se você precisar criar e indexar com duas ou mais colunas, você pode usar vírgulas. Por exemplo:

@Entity
@Table(name    = "company__activity", 
       indexes = {@Index(name = "i_company_activity", columnList = "activity_id,company_id")})
public class CompanyActivity{
Borjab
fonte
Obrigado a Alvin por sua resposta. (+1 voto). Mas eu tive que procurar algumas coisas a Espero que este exemplo possa tornar sua vida mais fácil
borjab
Exatamente o que eu estava procurando - um código simples e limpo cortado - não apenas descrevendo a coisa toda. Obrigado +1.
DominikAngerer
2
@borjab - você pode me dar uma dica de onde posso encontrar um exemplo ou especificação "oficial" para usar a @Indexanotação dentro da @Tableanotação? Pesquisei na JSR 338, mas não encontrei lá. Sua postagem é muito útil para mim.
JimHawkins de
2
@Ulrich Não é exatamente a documentação oficial, mas o blog oracle blogs.oracle.com/arungupta/entry/jpa_2_1_schema_generation
borjab
Eu me pergunto, se eu tenho uma coluna com @Column (unique = true), ela é mesclada com a lista de índices (já que único também é um índice)?
wkrueger
34

Uma coleção única de anotações de índice escolhida a dedo

= Especificações =

= Estruturas ORM =

= ORM para Android =

= Outro (difícil de categorizar) =

  • Reino - banco de dados alternativo para iOS / Android: anotaçãoio.realm.annotations.Index ;
  • Empire-db - uma camada de abstração de banco de dados relacional leve, porém poderosa, baseada em JDBC. Não tem definição de esquema por meio de anotações;
  • Kotlin NoSQL (GitHub) - um DSL reativo e de tipo seguro para trabalhar com bancos de dados NoSQL (PoC): ???
  • Slick - Mapeamento Relacional Funcional Reativo para Scala. Não possui definição de esquema por meio de anotações.

Basta ir para um deles.

naXa
fonte
31

JPA 2.1 (finalmente) adiciona suporte para índices e chaves estrangeiras! Veja este blog para detalhes. JPA 2.1 é uma parte do Java EE 7, que foi lançado.

Se você gosta de viver no limite, pode obter o instantâneo mais recente do eclipselink do repositório maven (groupId: org.eclipse.persistence, artifactId: eclipselink, versão: 2.5.0-SNAPSHOT). Apenas para as anotações JPA (que devem funcionar com qualquer provedor, uma vez que suportam 2.1), use artifactID: javax.persistence, versão: 2.1.0-SNAPSHOT.

Estou usando para um projeto que não será concluído antes de seu lançamento, e não notei nenhum problema horrível (embora não esteja fazendo nada muito complexo com ele).

ATUALIZAÇÃO (26 de setembro de 2013): Atualmente, as versões de lançamento e candidato a lançamento do eclipselink estão disponíveis no repositório central (principal), portanto, você não precisa mais adicionar o repositório eclipselink em projetos Maven. A última versão de lançamento é 2.5.0, mas 2.5.1-RC3 também está presente. Eu mudaria para 2.5.1 ASAP por causa de problemas com a versão 2.5.0 (o material do modelgen não funciona).

Alvin Thompson
fonte
9

No JPA 2.1, você precisa fazer o seguinte

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

No exemplo acima, a tabela TEST_PERSON terá 3 índices:

  • índice único no ID da chave primária

  • índice em AGE

  • índice composto em FNAME, SNAME

Nota 1: você obtém o índice composto tendo duas anotações @Index com o mesmo nome

Nota 2: você especifica o nome da coluna em columnList e não no fieldName

James Clayton
fonte
5

Eu realmente gostaria de poder especificar índices de banco de dados de uma forma padronizada, mas, infelizmente, isso não faz parte da especificação JPA (talvez porque o suporte à geração de DDL não seja exigido pela especificação JPA, que é uma espécie de obstáculo para tal recurso).

Portanto, você terá que contar com uma extensão específica do provedor para isso. Hibernate, OpenJPA e EclipseLink claramente oferecem tal extensão. Não posso confirmar para DataNucleus, mas como a definição de índices faz parte do JDO, acho que sim.

Eu realmente espero que o suporte ao índice seja padronizado nas próximas versões da especificação e, portanto, de alguma forma discorde de outras respostas, não vejo nenhuma boa razão para não incluir tal coisa no JPA (especialmente porque o banco de dados nem sempre está sob seu controle) para suporte de geração de DDL ideal.

A propósito, sugiro baixar a especificação JPA 2.0.

Pascal Thivent
fonte
4

Até onde eu sei, não existe uma forma de provedor JPA cruzado de especificar índices. No entanto, você sempre pode criá-los manualmente, diretamente no banco de dados, a maioria dos bancos de dados irá selecioná-los automaticamente durante o planejamento da consulta.

Tassos Bassoukos
fonte
2
lol, supondo que você tenha DBAs que fazem o trabalho de um DBA (:
Jacob
3
Acho um pouco estranho que haja uma maneira de fazer "exclusivo", mas não uma maneira de fazer um índice.
Jacob
7
@Jacob - Bem, é importante saber no nível do aplicativo se algum campo será exclusivo ou não. Os índices, por outro lado, têm como objetivo otimizar o acesso ao banco de dados. Não há necessidade (pelo que vejo) de saber se uma coluna é um índice ou não na camada java. Como você disse, o DBA pode configurar um índice se parecer que uma coluna específica se beneficiaria com isso.
Bebedor de Java
1
@Jacob, não há suporte para Índice porque isso é simplesmente uma otimização (normalmente importante, mas ainda assim uma otimização). OTOH se um campo (ou conjunto de campos) é único ou não depende do modelo e afetará a exatidão. Além disso, não há necessidade de um DBA 200USD / Hr completo, algumas instruções simples de criação de índice geralmente são suficientes.
Tassos Bassoukos
8
JPA 2.1 especificajavax.persistence.Index
Lukas Eder
2

EclipseLink forneceu uma anotação (por exemplo, @Index ) para definir um índice nas colunas. Há um exemplo de seu uso. Parte do exemplo está incluída ...

Os campos firstName e lastName são 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
fonte
1

O OpenJPA permite que você especifique uma anotação não padrão para definir o índice na propriedade.

Os detalhes estão aqui .

especialista
fonte
0

Não é possível fazer isso usando a anotação JPA. E isso faz sentido: onde um UniqueConstraint define claramente as regras de negócios, um índice é apenas uma forma de tornar a pesquisa mais rápida. Portanto, isso realmente deve ser feito por um DBA.

Thierry-Dimitri Roy
fonte
0

Esta solução é para EclipseLink 2.5 e funciona (testado):

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

Isso pressupõe ordem ascendente.

Joe Almore
fonte