Estou desenvolvendo uma aplicação em Ruby on Rails com o banco de dados PostgreSQL (9.4). Para o meu caso de uso, as colunas nas tabelas serão pesquisadas com muita frequência, pois o objetivo principal do aplicativo é procurar atributos muito específicos em um modelo.
Atualmente estou decidindo se devo usar um integer
tipo ou simplesmente usar um tipo de string típico (por exemplo character varying(255)
, que é o padrão em Rails ) para as colunas, pois não tenho certeza de qual será a diferença de desempenho no índice.
Essas colunas são enumerações . Eles têm um tamanho fixo para a quantidade de valores possíveis que podem ter. A maioria dos comprimentos de enumeração não excede 5, o que significa que o índice seria mais ou menos fixo durante toda a vida útil do aplicativo ; assim, os índices integer e string seriam idênticos no número de nós.
No entanto, a string que seria indexada pode ter cerca de 20 caracteres, o que na memória é aproximadamente 5x o número inteiro (se um inteiro tiver 4 bytes e as strings forem ASCII puro em 1 byte por caractere, isso será válido). Eu não sei como os mecanismos de banco de dados fazem pesquisas de índice, mas se ele precisar "varrer" a string até que ela corresponda exatamente , então, em essência, isso significa que a pesquisa de string seria 5x mais lenta que uma pesquisa de inteiro; o "scan" until match para a pesquisa de inteiros seria de 4 bytes em vez de 20. Isto é o que estou imaginando:
O valor de pesquisa é (inteiro) 4:
digitalização......................... ENCONTRADO | obtendo registros... |BYTE_1|BYTE_2|BYTE_3|BYTE_4|BYTE_5|BYTE_6|BYTE_7|BYTE_8|...|
O valor de pesquisa é (string) "some_val" (8 bytes):
digitalização.................................................. .................................... ENCONTRADO | obtendo registros... |BYTE_1|BYTE_2|BYTE_3|BYTE_4|BYTE_5|BYTE_6|BYTE_7|BYTE_8|...|
Espero que isso faça sentido. Basicamente, como o inteiro ocupa menos espaço, ele pode ser "combinado" mais rapidamente do que sua contraparte de string. Talvez este seja um palpite completamente errado, mas eu não sou especialista, então é por isso que estou perguntando a vocês! Suponho que esta resposta que acabei de encontrar parece apoiar minha hipótese, mas quero ter certeza.
O número de valores possíveis na coluna não mudaria usando nenhum deles, então o índice em si não mudaria (a menos que eu adicionasse um novo valor ao enum). Nesse caso, haveria uma diferença de desempenho em usar integer
ou varchar(255)
, ou usar um tipo inteiro faz mais sentido?
A razão pela qual estou perguntando é que o enum
tipo do Rails mapeia inteiros para chaves de string, mas eles não devem ser colunas voltadas para o usuário. Essencialmente, você não pode verificar se o valor enum é válido, porque um valor inválido causará um erro ArgumentError
antes que qualquer validação possa ser executada. Usar um string
tipo permitiria validações, mas se houver um custo de desempenho, prefiro apenas contornar o problema de validação.
Resposta curta:
integer
é mais rápido do quevarchar
outext
em todos os aspectos. Não importa muito para mesas pequenas e/ou teclas curtas. A diferença cresce com o comprimento das chaves e o número de linhas.Para ser preciso, os tipos de caracteres (
text
ouvarchar
) ocupam exatamente 21 bytes para 20 caracteres ASCII no disco e 23 bytes na RAM. Avaliação detalhada:Também importante:
COLLATION
as regras podem tornar a classificação de dados de caracteres mais cara - ao contrário dos tipos de dados numéricos:O tamanho do índice é provavelmente responsável pela maior parte da diferença de desempenho na maioria dos casos. Considere a sobrecarga por tupla de índice (basicamente a mesma que para uma tabela): 4 bytes para o identificador de item e 8 bytes para o cabeçalho da tupla de índice. Portanto, a tupla de índice para
integer
seria de 20 bytes (incluindo 4 bytes de preenchimento de alinhamento ) e paravarchar(20)
com 20 caracteres ASCII seria de 36 bytes (incluindo preenchimento). Detalhes:Toda a teoria de lado: é melhor apenas testar:
O Postgres 9.5 introduziu uma otimização para classificar longas cadeias de dados de caracteres (palavra-chave "chaves abreviadas" ). Mas um bug em algumas funções da biblioteca C no Linux forçou o projeto a desabilitar o recurso para agrupamentos não-C no Postgres 9.5.2. Detalhes nas notas de lançamento.
No entanto, se você realmente usa tipos Postgres
enum
, a maioria dessas considerações é irrelevante, já que elas são implementadas comreal
valores internamente de qualquer maneira. O manual:Aparte:
varchar(255)
usado para fazer sentido para as primeiras versões do SQL Server, que poderiam usar um tipo de dados mais eficiente internamente até o limite de 255 caracteres. Mas a restrição de comprimento ímpar de 255 caracteres não tem nenhum significado especial no Postgres.