Como os recursos avançados do PostgreSQL podem ajudar o desenvolvedor de aplicações rails.
mas antes de mais nada...
• Essa palestra não é...
• ... um início de uma guerra com os entusiastas de opções
NoSQL (me considero um deles).
• ... uma tentativa de pintar o PostgreSQL como a cura de
todos os males.
prelúdio 2
• Eu, Diogo Biazus:
• Sócio fundador da Softa e
posteriormente Engage
• Equipe de
desenvolvimento do Mailee.me
Apresentando: PostgreSQL
• Um elefante? Pensem: Poderoso e robusto (e não gordo e
lento).
• O slogan “The world’s most advanced open source database”
não é exagero.
• https://github.com/postgres/postgres
E por que não seria?
• A tecnologia dos SGBDRs é muito madura e evoluiu muito
nos últimos 30 anos.
Desenvolvedores Rails
• “I don't want my database to be clever!” - DHH • Parecem gostar de DSLs.
• Compreendem “A ferramenta certa para o problema”.
Usando Constraints
• Se a integridade é importante, o SGDB é seu amigo. • https://github.com/matthuhiggins/foreigner
• add_foreign_key(from_table, to_table, options) • add_index(table, [fields], :unique => true)
Usando Constraints
• NOT NULL pelamordedeus!!!
• Se usamos um validates_presence_of, porque não usar um
NOT NULL?
• Se usamos um validates_uniqueness_of que tal um daqueles
Usando Visões no Banco
• Visões podem facilitar a modelagem, criar modelos em níveis
mais altos de abstração.
• Modelos do AR as enxergam normalmente (só para leitura). • Podemos relacioná-las com outros modelos e facilitar nossa
vida (pensem em agregações, slugs, etc...).
Colisões de Períodos
• Feio:
• Overlaps é um operador sexy e muito pouco usado
• Sexy:
SELECT *
FROM meetings m1, meetings m2
WHERE (m2.starts_at, m2.ends_at) OVERLAPS (m1.starts_at, m1.ends_at)
AND m1.id > m2.id; SELECT *
FROM meetings m1, meetings m2
WHERE (m2.starts_at BETWEEN m1.starts_at AND m1.ends_at OR m2.ends_at BETWEEN m1.starts_at AND m1.ends_at)
Geolocalização
• Como calcular distâncias usando lat/lng?
• Geokit: Faz várias coisas, muito bom para geocoding (e bem
popular segundo o ruby-toolbox.com).
• Earthdistance: É rápido para distâncias e áreas (com índices
GiST/GIN).
Geolocalização
• Todos gostamos de benchmarks!
• Pesquisa de vários raios de 1 a 1.000 metros com 1.590 locais • https://github.com/diogob/test_geokit
• query geokit (288.449,9ms)
Dados Hierárquicos
• Nested sets approach (https://github.com/collectiveidea/
awesome_nested_set)
• WITH RECURSIVE
Dados Desestruturados
• Campo serializado em coluna de texto.
• https://github.com/softa/activerecord-postgres-hstore • Hstore, podemos usar índices.
Dados Desestruturados
• Nesse caso o eixo x é
tempo
• Isso significa que o vermelho
é algumas ordens de magnitude mais rápido
• Claro que poderíamos usar
índices de trigramas para acelerar o azul :D
Dados Desestruturados
• O salvamento e atualização é transparente, basta salvar um hash
no campo do tipo hstore.
• Registros com chave foo: Person.where("data ? 'foo'")
• Registros onde foo = bar: Person.where("data -> 'foo' = 'bar'") • Agora com índices: Person.where("data @> 'foo=>bar'")
Full Text Search
• Mecanismo nativo para busca de palavras chave. • Desacentuação (contrib).
• Análise de trigramas (contrib).
• https://github.com/Casecommons/pg_search • https://github.com/tenderlove/texticle
pg_search
• Multisearch e Search Scopes
• Multisearch: Escopo de pesquisa global, cria tabela adicional :( • Ótimo suporte aos recursos de FTS nativos do PostgreSQL • Suporte aos contribs pg_trgm, fuzzystrmatch e unaccent
pg_search
class BlogPost < ActiveRecord::Base include PgSearch
pg_search_scope :search_by_title, :against => :title end
class Beer < ActiveRecord::Base include PgSearch
pg_search_scope :search_name, :against => :name, :using => [:tsearch, :trigram, :dmetaphone]
pg_search e o tsearch
class Superhero < ActiveRecord::Base include PgSearch
pg_search_scope :whose_name_starts_with, :against => :name,
:using => {
:tsearch => {:prefix => true} }
end
batman = Superhero.create :name => 'Batman' batgirl = Superhero.create :name => 'Batgirl' robin = Superhero.create :name => 'Robin'
Tabelas sem Log de Transação
• Modificação rápida
• Tabela é truncada em caso de falha • Pequeno teste
Importação em Warp Speed
• A importação de dados de CSV inocente:
require 'csv'
ActiveRecord::Base.transaction do
CSV.foreach("#{Rails.root}/db/test100.csv") do |row|
self.create!(:data1 => row[0], :data2 => row[1], :data3 => row[2], :data4 => row[3])
end end
Importação em Warp Speed
• A importação de dados de CSV usando copy:
self.pg_copy_from("#{Rails.root}/db/test100.csv", {:delimiter => ','})
Enquanto isso no mundo
assíncrono
• A libpq implementa chamadas assíncronas há muitos anos, e
elas estão disponíveis na gem pg para ruby
• As conexões do PostgreSQL suportam notificações
assíncronas com LISTEN e NOTIFY, o que o torna uma opção atraente para o pessoal trabalhando com EM, Goliath,
Precisamos de mais buzzwords
• A Nuvem!
• https://postgres.heroku.com/ • em beta na EY
Referências
• http://www.postgresql.org • http://david.heinemeierhansson.com/arc/2005_09.html • http://zoomquiet.org/res/scrapbook/ZqFLOSS/data/ 20101118093144/index.html • https://www.ruby-toolbox.com/ •http://stackoverflow.com/questions/689458/find-overlapping-Muito Obrigado
Diogo Biazus (@dbiazus) Engage (http://engage.is)