PostgreSQL e porque você não precisa de NoSQL Matheus de Oliveira <matheus.oliveira@dextra.com.br>
Matheus de Oliveira <matheus.oliveira@dextra.com.br> DBA PostgreSQL consultorias e suportes 24x7/8x5 Instrutor dos treinamentos PostgreSQL Concepção, desenvolvimento e suporte à produção
Matheus de Oliveira <matheus.oliveira@dextra.com.br> Mais de 15 anos trabalhando de suporte e consultoria PostgreSQL http://www.dextra.com.br/ Crafting Software, Transforming Business Instrutor dos treinamentos PostgreSQL Concepção, desenvolvimento e suporte à produção
Matheus de Oliveira <matheus.oliveira@dextra.com.br> 10 anos e mais de 10 mil profissionais capacitados em todo o Brasil. http://www.dextraining.com.br/ Aprenda com quem faz na prática Mais de 15 anos trabalhando de suporte e consultoria PostgreSQL http://www.dextra.com.br/ Crafting Software, Transforming Business Concepção, desenvolvimento e suporte à produção
Matheus de Oliveira <matheus.oliveira@dextra.com.br> 10 anos e mais de 10 mil profissionais capacitados em todo o Brasil. http://www.dextraining.com.br/ Aprenda com quem faz na prática Mais de 15 anos trabalhando de suporte e consultoria PostgreSQL http://www.dextra.com.br/ Crafting Software, Transforming Business SaaS para análise e monitoramento PostgreSQL http://www.pganalytics.com.br/ Facilitando a vida do DBA
Para pensar... A melhor solução para o seu problema agora VS A melhor solução de todas, à todo custo 3 / 48
Para pensar... A melhor solução para o seu problema agora VS A melhor solução de todas, à todo custo 3 / 48
Para pensar... Cuidado com o que você pensa ser moderno. Armazenamentos chave/valor e documentos datam de antes das teorias de bancos relacionais. A teoria relacional é baseada numa forte e sólida estrutura, e revolucionou o armazenamento de processamento de dados. Abrir mão disso por completo é regredir. 4 / 48
Bancos de dados relacionais e NoSQLs Bancos relacionais: Baseados no modelo relacional Transações ACID Atomicidade Consistência Isolamento Durabilidade 5 / 48 Interface de consulta padrão SQL Armazenamento em relações estrutura acoplada... Bancos NoSQL: Transações BASE: Basic Availability Soft-state Eventual consistency Interface de consulta própria Schemaless: Chave-Valor Documento Grafos... Performance como prioridade In-place update Operações assíncronas...
PostgreSQL one database to rule them all FOSS Free Open Source Software Quase 30 anos de experiência Robustez, confiabilidade, maturidade Diversas funcionalidades, e novas a cada versão Forte extensibilidade 6 / 48
Você não precisa de NoSQL para: chave/valor
hstore Armazenamento chave/valor Presente como uma contrib do PostgreSQL desde a versão 8.3 (2008) Armazenamento de chaves/valores como atributo (coluna) de uma tabela Diversos operadores para manipulação, navegação e filtragem (busca) Indexação B-tree, GIN e GIST Exemplo: SELECT * FROM movies WHERE ( moviedata -> imdb_rate ) :: int > 4 AND moviedata -> alternate_title = Black Mask ; 8 / 48
hstore Armazenamento chave/valor Limitações: Aceita apenas texto, tanto para chave quanto para valor Não aceita valores aninhados (hstore de hstore) Alternativas NoSQL: Redis Riak MemcacheDB Berkeley DB Dynamo... 9 / 48
Você não precisa de NoSQL para: documentos JSON
JSON 2012 versão 9.2 tipo json, basicamente text com validações 2013 versão 9.3 ainda json, mas com funções fantásticas (a grande adoção começa) 2014 versão 9.4 (hoje em beta2) tipo jsonb, binário (estrutura interna baseada no hstore), indexação GIN ultra-blaster-rápido 11 / 48
JSON CREATE TABLE booksdata ( title text PRIMARY KEY, booksdata jsonb ); 12 / 48
JSON SELECT title, bookdata ->> current_edition AS edition, bookdata #> {" publication_info ", 0, " isbn "} AS isbn FROM booksdata WHERE bookdata @ > { " publication_info " : [{" publisher ": " Avon "} ] } :: jsonb ORDER BY bookdata #> {" publication_info ", 0, " price "} DESC ; 13 / 48
JSON Ah!!! E eu comentei que é indexado? 14 / 48
JSON Ah!!! E eu comentei que é indexado? DE VERDADE CREATE INDEX booksdata_json_idx ON booksdata USING GIN ( booksdata ); 14 / 48
JSON Ah!!! E eu comentei que é indexado? DE VERDADE CREATE INDEX booksdata_json_idx ON booksdata USING GIN ( booksdata ); GIN to the rescue!!! 14 / 48
JSON Limitações: O tipo json é armazenado em texto e possui fraca indexação, mas sua evolução, o tipo jsonb é armazenado em binário Diferente do json, o jsonb possui as limitações: não armazena a ordem original das chaves (elas sempre serão mostradas em ordem lexicográfica) não aceita chaves repetidas (basicamente json armazena exatamente como você passa, mas jsonb faz um processamento extra) Eu diria que hoje, o PostgreSQL possui o mais avançado mecanismo de indexação para JSON (jsonb) dos bancos de dados open sources (de todos? provavelmente) 15 / 48
JSON Alguns NoSQLs orientado à documentos: MongoDB CouchDB Cassandra SimpleDB... 16 / 48
Você não precisa de NoSQL para: Full Text Search
Full Text Search FTS nativo no PostgreSQL (tsvector, tsquery,...) SELECT * FROM articles t( fts ) WHERE fts @@ tsquery PostgreSQL & NewSQL ORDER BY ts_ rank ( fts, tsquery PostgreSQL & NewSQL ); Busca por similaridade (contrib pg trgm) SELECT set_limit (0.2) ; SELECT *, title <- > NewSQL AS sml FROM articles WHERE title % NewSQL ORDER BY sml DESC LIMIT 10; 18 / 48
Full Text Search FTS nativo no PostgreSQL (tsvector, tsquery,...) SELECT * FROM articles t( fts ) WHERE fts @@ tsquery PostgreSQL & NewSQL ORDER BY ts_ rank ( fts, tsquery PostgreSQL & NewSQL ); Busca por similaridade (contrib pg trgm) SELECT set_limit (0.2) ; SELECT *, title <- > NewSQL AS sml FROM articles WHERE title % NewSQL ORDER BY sml DESC LIMIT 10; Claro, tudo devidamente indexado... GIN and GIST rocks 18 / 48
Full Text Search Limitações: Não processa documentos como PDF, DOC, etc. Até a versão 9.4 performance mais baixa para algumas operações (como ordenação por maior similaridade) GIN evoluiu na versão 9.4 Alguns NoSQLs com FTS: Solr Lucene Elastic Search Sphinx e também MySQL 19 / 48
Você não precisa de NoSQL para: grafos e hierarquias
Consultas em grafos e hierarquias Pode ser facilmente realizada utilizando consultas recursivas O desempenho depende do filtro e profundidade da navegação Exemplo, catálogo de roles (usuários/grupos) do PostgreSQL: WITH RECURSIVE roles AS ( SELECT r. oid AS roleid, r. rolname, 1 AS level, array [ r. rolname ] AS path FROM pg_authid r WHERE r. oid NOT IN ( SELECT m. member FROM pg_ auth_ members m) UNION ALL SELECT r. oid, r. rolname, p. level + 1, p. path r. rolname FROM pg_ auth_ members m INNER JOIN pg_authid r ON m. member = r. oid INNER JOIN roles p ON m. roleid = p. roleid ) SELECT repeat (, level -1) rolname FROM roles ORDER BY path ; 21 / 48
Consultas em grafos e hierarquias Resultado: administrativo comercial carla maria financeiro ana paulo ti beatriz julio matheus... 22 / 48
Consultas em grafos e hierarquias Limitações: Um pouco complexo, mas você acostuma Performance dependente principalmente da altura Não muito bem preparado para busca em espaços de buscas grandes ou estruturas de grafos complexas Bancos NoSQL orientados à grafos: Neo4j OrientDB... 23 / 48
Você não precisa de NoSQL para: operações assíncronas
Operações assíncronas Quando não precisamos garantir durabilidade em tempo real: Habilite o parâmetro synchronous commit: SET synchronous_commit TO off ; Para dados transientes: UNLOGGED TABLES Quando precisamos de operações não bloqueantes: PQsendQuery, PQsendPrepare, PQconsumeInput, PQisBusy,... Processamento de mensagens: Sincronia pode ser atingida com auxílio de advisory locks Troca de mensagens (ativação, pull/push, sender/receiver, etc.) com LISTEN/NOTIFY 25 / 48
Exemplo de fila Ideia: Processos a executar são guardados numa tabela: CREATE TABLE queue ( id serial, processed boolean default false,..., job jsonb ); Para inserir um job para execução: BEGIN ; INSERT INTO queue ( job ) VALUES ( {" jobname ": " foo ",...} ); NOTIFY jobexecutor ; COMMIT ; /* NOTIFY dispara somente depois */ job executors ficam aguardando processos a executar: LISTEN jobexecutor ; 26 / 48 e buscam trabalhos da fila...
Exemplo de fila job executor 1 UPDATE queue 2 SET processed = true 3 WHERE NOT processed AND id IN ( 4 SELECT id FROM ( 5 SELECT id FROM queue 6 WHERE NOT processed 7 ORDER BY id 8 LIMIT 100 9 ) t 10 WHERE 11 pg_try_advisory_xact_lock ( 12 tableoid :: int, id ) 13 ORDER BY id 14 LIMIT 1 15 ) 16 RETURNING job ; 27 / 48
Exemplo de fila job executor 1 UPDATE queue 2 SET processed = true 3 WHERE NOT processed AND id IN ( 4 SELECT id FROM ( 6 SELECT id FROM queue 7 WHERE NOT processed 8 ORDER BY id 9 LIMIT 100 10 ) t 11 WHERE 12 pg_try_advisory_xact_lock ( 13 tableoid :: int, id ) 14 ORDER BY id 15 LIMIT 1 16 ) 17 RETURNING job ; 28 / 48
Exemplo de fila job executor 1 UPDATE queue 2 SET processed = true 3 WHERE NOT processed AND id IN ( 4 SELECT id FROM ( 6 SELECT id FROM queue 7 WHERE NOT processed 8 ORDER BY id 9 LIMIT 100 10 ) t 11 WHERE 12 pg_try_advisory_xact_lock ( 13 tableoid :: int, id ) 14 ORDER BY id 15 LIMIT 1 16 ) 17 RETURNING job ; 29 / 48
Exemplo de fila job executor 1 UPDATE queue 2 SET processed = true 3 WHERE NOT processed AND id IN ( 4 SELECT id FROM ( 6 SELECT id FROM queue 7 WHERE NOT processed 8 ORDER BY id 9 LIMIT 100 10 ) t 11 WHERE 12 pg_try_advisory_xact_lock ( 13 tableoid :: int, id ) 14 ORDER BY id 15 LIMIT 1 16 ) 17 RETURNING job ; 30 / 48
Fila Limitações: Uso de funções não específicas de SQL Um pouco complicadinho, não acham? Outras opções (não só NoSQL): pgq fila alta performance em PostgreSQL RabbitMQ ActiveMQ MongoDB (tailable cursors)... 31 / 48
Você não precisa de NoSQL para: atualizações rápidas
Usando ACID em alta concorrência PostgreSQL é 100% ACID compilante Isso nos traz um poderoso controle de transações Mas... Para ter transação, precisamos de bloqueios, mais conhecido como locks 33 / 48
Usando ACID em alta concorrência No PostgreSQL locks são podem ser: de vários modos compartilhados, exclusivo, acesso exclusivo, etc. definidos pelo usuário advisory locks em vários níveis tuplas, páginas, tabelas, etc. São essenciais (acredite, não vai querer abrir mão disto) Mas... Muitas vezes precisamos ter um certo trabalho para reduzir o número ou tempo de bloqueios 34 / 48
Usando ACID em alta concorrência Regra no PostgreSQL: escritores nunca bloqueiam leitores e leitores nunca bloqueiam escritores nem outros leitores (mas escritores bloqueiam escritores) 35 / 48
Exemplo... Vamos supor contagem de número de acessos à uma página, onde precisamos dessa informação precisa e fácil de consultar. Logo nos vêm à cabeça: UPDATE page_ info SET access_ count = access_ count + 1 WHERE url = : url ; Para consultar, basta: SELECT access_ count FROM page_ info WHERE url = : url ; 36 / 48
Exemplo... UPDATE page_ info SET access_ count = access_ count + 1 WHERE url = : url ; Alguém vê o problema no cara acima? 37 / 48
Exemplo... UPDATE page_ info SET access_ count = access_ count + 1 WHERE url = : url ; Alguém vê o problema no cara acima? Cada transação concorrente executando esta operação ficará bloqueada, ou seja, apenas uma pessoa pode executar este comando por vez (por url). 37 / 48
Solução... 1. Ao invés de atualizar, vamos inserir: INSERT INTO page_ access ( url, access_ count ) VALUES (: url, 1) ; 2. Para consultar usamos um agregador: SELECT sum ( access_ count ) FROM page_ access WHERE url = : url ; 3. E claro, agora trocamos um UPDATE bloqueante por um SELECT potencialmente lento. Calma... Calma... Tem solução! 38 / 48
Solução... Para resolver o problema da consulta ficar lenta, devemos de tempos em tempos agrupar os registros da tabela WITH old_ itens AS ( DELETE FROM page_ access RETURNING url, access_ count ) INSERT INTO page_ access ( url, access_ count ) SELECT url, sum ( access_ count ) FROM old_ itens GROUP BY url ; Esta operação é completamente não bloqueante! Enquanto está sendo executada os INSERTs continuam e os SELECTs também. 39 / 48
Solução... Para resolver o problema da consulta ficar lenta, devemos de tempos em tempos agrupar os registros da tabela WITH old_ itens AS ( DELETE FROM page_ access RETURNING url, access_ count ) INSERT INTO page_ access ( url, access_ count ) SELECT url, sum ( access_ count ) FROM old_ itens GROUP BY url ; BTW, o comando WITH lá em cima é conhecido como CTE (Common Table Expressions), e é de grande utilidade. #ficaadica 39 / 48
Solução... Para resolver o problema da consulta ficar lenta, devemos de tempos em tempos agrupar os registros da tabela WITH old_ itens AS ( DELETE FROM page_ access RETURNING url, access_ count ) INSERT INTO page_ access ( url, access_ count ) SELECT url, sum ( access_ count ) FROM old_ itens GROUP BY url ; Por fim, adicione um índice em url e seja feliz: #ficaadica2 CREATE INDEX ON page access count (url); 39 / 48
...
Performance O PostgreSQL é, sem dúvidas, um dos bancos de dados com melhores desempenhos num único nó. Devemos sempre olhar para: ajuste (tuning) de parâmetros de configuração; indexação; modelo de dados (normalizar ou desnormalizar); tarefas administrativas; estatísticas atualizadas;... busque por PostgreSQL Performance Tuning... 41 / 48
Performance E quando precisamos de mais: columnar store (extensões para o PostgreSQL cstore fdw 1 e In-Memory Columnar Store (ICMS) 2 ); particionamento de tabelas; divisão de tablespaces; 42 / 48
Performance Escalabilidade horizontal: replicação: replicação nativa com slave disponível para consulta (balanceamento de carga para consultas); replicação multi-master com ferramentas externas: Bucardo e BDR (a grande promessa para a versão 9.4). técnicas de sharding e/ou processamento de consulta em paralelo: divisão de processos em conexões; sharding via aplicação; sharding via postgres fdw 3. 1 http://citusdata.github.io/cstore_fdw/ 2 http://www.garret.ru/imcs/user_guide.html 3 http: //www.infoq.com/br/presentations/postgresql-com-newsql 43 / 48
E quando o PostgreSQL não resolve meu problema? Primeiro, tem certeza que não? 44 / 48
E quando o PostgreSQL não resolve meu problema? Primeiro, tem certeza que não? Absoluta? 44 / 48
E quando o PostgreSQL não resolve meu problema? Ok, acontece... sobrecarga de operações e do MVCC pode gerar gargalos; sem processamento paralelo ou sharding nativo (apenas o faça você mesmo ); falta de funcionalidades frente à banco de dados especializados, exemplos: estruturas de grafos são melhores tratadas em especializados como Neo4j do que com consultas recursivas; FTS do PostgreSQL comparado à outros como Lucene ou Sphinx ainda perde em funcionalidades. 45 / 48
E quando o PostgreSQL não resolve meu problema? Mas tudo bem usar outro. Se quiser associar, vários Foreign Data Wrappers (FDW) estão disponíveis (redis fdw, mongo fdw,...) para mapear dados externos dentro de tabelas no PostgreSQL; 46 / 48
E quando o PostgreSQL não resolve meu problema? DICA DE OURO: comece sempre no PostgreSQL (tiro certo), se o projeto crescer fora de escala que o PG suporte, busque outras alternativas. É muito comum utilizar bancos NoSQL junto com bancos relacionais (não é escolha única). Existem muitos bancos MPP (Massive Parallel Processing) e (100%) NewSQL baseados no PostgreSQL. comerciais: Greenplun, Amazon Redshift, Aster Data, Netezza, Vertica, entre outros; e as promessas open source: Postgres-XC e Postgres-XL. 47 / 48
Obrigado! Dúvidas? Matheus de Oliveira <matheus.oliveira@dextra.com.br> IRC irc.freenode.net: /join #postgresql,#postgresql-br,#dextra Meu nick: MatheusOl Twitter: @matioli matheus LinkedIn: br.linkedin.com/in/matheusdeoliveira/ SlideShare: slideshare.net/matheus de oliveira