Não, pera. Para tudo.
Esquece o que eu falei sobre index por enquanto.
Você pode colocar o CPF como chave primária, colocando algo como:
Certo? Se você não quer que seja chave primária, coloca algo como:
@Id
private long id;
private String cpf;
No caso que o CPF não é chave primária, você pode colocar uma constraint no CPF dizendo que ele deve ser único. Dessa forma, caso você tente inserir um CPF duplicado, vai acontecer um erro de validação no JPA Provider (hibernate, por exemplo). Para fazer isso, você faz assim:
@Id
private long id;
@Column(unique=true)
private String cpf;
Essa constraint é avaliada pelo JPA provider. Caso você queira que exista realmente uma constraint física no banco de dados, você deve fazer assim:
@Entity
@Table(uniqueConstraints={@UniqueConstraint(columnNames={"cpf"})})
public class Usuario {...}
Onde cpf é o nome da coluna no DB. Essa constraint física vai ser criada se é o JPA Provider que está gerando suas tabelas.
Como o @jonas.cant falou, não é legal utilizar o CPF como chave primária mesmo. Eu recomendo a utilização de boas práticas independente da situação, mas se você tá fazendo um projetinho pra aprender ou algo do gênero, não se preocupe, vai cair tua mão se você profanar os dogmas da comunidade.
Entendendo o Index
Um index, no banco de dados, nada mais é do que um local onde é armazenado algumas colunas de uma tabela que você pode escolher. O index é uma cópia dessas colunas, e pode ter as vezes referências diretas às linhas correspondentes, ou até mesmo o endereço do bloco no disco onde aquele dado está armazenado fisicamente.
A vantagem principal de um index é a rapidez para se recuperar dados, quando o parâmetro de busca está em uma coluna que está no index.
Uma coluna que sempre está no index de uma tabela, por padrão, é sua chave primária! Por isso é tão mais rápido buscar pela chave primária.
Você pode adicionar quantas colunas você quiser ao index. No seu caso, por exemplo, você pode adicionar o cpf também, agilizando a busca.
Você provavelmente vai se perguntar: Então, porque não colocar a tabela inteira dentro do index? Não é mais rápido?
Resposta: Não! Manter o index é custoso. O banco de dados tem que lidar com dados duplicados, o que pode ser um problema de escalabilidade. Use com sabedoria!
Outra pergunta: como é que o banco de dados sabe que é pra usar o index na hora da busca, e não a coluna normal?
Resposta: Existe um mecanismo no DB chamado de Query Planner. Quando você manda uma query para o DB, ele não a executa logo de cara. Ele analisa tua query e tenta otimiza-la da melhor forma possível. Isso inclui utilizar o index, se for possível.
Agora sim, voltando para o teu caso.
Se você quiser que o JPA Provider construa os index no DB para você, pode utilizar o atributo que citei anteriormente, o indexes, na annotation @Table. Assim:
@Entity
@Table(indexes = {@Index(name = "i_cpf", columnList = "cpf"))})
public class Usuario {...}
Você pode colocar mais colunas se quiser, ali no columnList, dentro da mesma string, separando por vírgula, por exemplo: "cpf,nome,idade". Definindo esse atributo, o JPA Provider, na hora que estiver construindo teu banco de dados, vai criar um index chamado de acordo com o atributo name, e colocar nele as colunas dentro do atributo columnList. Mas como eu falei, não é o JPA que vai utilizar o index na hora da busca, e sim o query planner do banco de dados.
Sacou?