[SP-pm] DBIx::Class

Eden Cardim eden at insoli.de
Thu Sep 19 06:53:30 PDT 2013


>>>>> "Lucas" == Lucas Oliveira <lucasmateus.oliveira em gmail.com> writes:

    Lucas> Show, sobre o MD5 que falei aqui tem um benchmark recente e
    Lucas> bacana.
    Lucas> http://www.big.info/2013/05/some-useful-mysql-database-md5-binary16.html

É MUITO estranho que uma consulta de look-up simples leve 56 segundos,
mesmo pro mysql e mesmo com 2M registros. Tem algo errado com esse
teste aí.

Fiz um benchmark similar aqui com postgres 9.1.9:

Um varchar de 10M caracteres, que é relativamente grande.

edenc=# create table test (id serial primary key, mystring varchar(10000000));                                                                                                       
NOTICE:  CREATE TABLE will create implicit sequence "test_id_seq" for serial column "test.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 177.671 ms

Povoei 2M colunas com textos de tamanhos aleatórios:

edenc=# insert into test (mystring) select repeat(n::text, (random() * 1000 + 1)::int) from generate_series(1,2000000) as n;                                                         
INSERT 0 2000000
Time: 199198.163 ms

Achei um registro que coubesse na tela:

edenc=# select mystring from test where length(mystring) < 100 limit 1;
                                       mystring                                       
--------------------------------------------------------------------------------------
 198872419887241988724198872419887241988724198872419887241988724198872419887241988724
(1 row)

Time: 2.437 ms

E consultei a tabela sem usar índice:

edenc=# select mystring from test where mystring = '198872419887241988724198872419887241988724198872419887241988724198872419887241988724';
                                       mystring                                       
--------------------------------------------------------------------------------------
 198872419887241988724198872419887241988724198872419887241988724198872419887241988724
(1 row)

Time: 503.553 ms

Depois criei o índice:

edenc=# create index on test (mystring);
CREATE INDEX
Time: 369215.286 ms

E repeti a consulta:

edenc=# select mystring from test where mystring = '198872419887241988724198872419887241988724198872419887241988724198872419887241988724';
                                       mystring                                       
--------------------------------------------------------------------------------------
 198872419887241988724198872419887241988724198872419887241988724198872419887241988724
(1 row)

Time: 8.819 ms

Obviamente, tem um fator distorcendo esses resultados, que é o page
cache do kernel e os shared buffers do pg que foram construídos
durante a escrita da tabela e o shared buffer cache do pg. Então eu
reiniciei a máquina pra garantir que não havia cache de kernel nem de
buffer:

edenc=# select mystring from test where mystring = '198872419887241988724198872419887241988724198872419887241988724198872419887241988724';
                                       mystring                                       
--------------------------------------------------------------------------------------
 198872419887241988724198872419887241988724198872419887241988724198872419887241988724
(1 row)

Time: 336.108 ms

E uma segunda query:

edenc=# select mystring from test where mystring = '198872419887241988724198872419887241988724198872419887241988724198872419887241988724';
                                       mystring                                       
--------------------------------------------------------------------------------------
 198872419887241988724198872419887241988724198872419887241988724198872419887241988724
(1 row)

Time: 0.380 ms

Que é bem mais rápida porque na segunda consulta, as páginas
relevantes da tabela (e *não* o resultado) foram cacheadas.

Obviamente, não é um teste perfeito, mas dá pra ter uma idéia da
falácia. Enfim, chaves artificiais como otimização são quase sempre
desnecessárias. O motivo é que com o índice certo (uma árvore de
busca), num campo unique, o banco de dados *nunca* vai ter que
comparar a string inteira. Olhem por exemplo o plano que é gerado
quando se trata de um like:

edenc=# explain select mystring from test where mystring like '1111%';
                                        QUERY PLAN                                        
------------------------------------------------------------------------------------------
 Index Scan using test_mystring_idx on test  (cost=0.00..3384.37 rows=200 width=359)
   Index Cond: (((mystring)::text >= '1111'::text) AND ((mystring)::text < '1112'::text))
   Filter: ((mystring)::text ~~ '1111%'::text)
(3 rows)




More information about the SaoPaulo-pm mailing list