de vuelta al pasado con sql y stored procedures
DESCRIPTION
El uso de stored procedures está muy difundido entre los administradores de bases de datos como una forma de encapsular la lógica de datos de las aplicaciones. La comunidad de desarrolladores web, sin embargo, nunca los adoptó plenamente porque siempre ha tenido dudas acerca de su portabilidad y mantenibilidad, además de una antipatía generalizada por SQL.De todos modos, la alternativa que se utiliza actualmente, la dupla abstracción de base de datos-ORM, también tiene sus propios problemas: baja performance, subutilización de las funciones avanzadas de bases de datos, y sintaxis de queries ad-hoc que terminan siendo más complicadas que el propio SQL.La creciente popularidad de las bases de datos NoSQL pone de manifiesto que los desarrolladores web contemporáneos están de nuevo dispuestos a considerar librerías de bases de datos específicas del vendedor para el desarrollo de aplicaciones. Entonces veamos qué es lo que tiene para ofrecernos un vendedor en particular: PostgreSQL.En esta charla voy a demostrar que crear una API basada en una mezcla de objetos Ruby sencillos y stored procedures de Postgres puede ser una opción muy convincente como sustituto de ORM.TRANSCRIPT
Norman Clarke
Business Vision Ruby Labs@compay
Volver al futuro con SQL y stored procedures
Wednesday, November 9, 11
Wednesday, November 9, 11
Wednesday, November 9, 11
Wednesday, November 9, 11
Lo que les espera...
• Características, ventajas y desventajas de stored procedures
• Una librería experimental basada en stored procedures
• Stored procedures vs. ORM
Wednesday, November 9, 11
Stored Proceduresprogramación "real" con SQL
Wednesday, November 9, 11
postgres=# select greeting();
greeting ------------- hello world!
(1 row)
Wednesday, November 9, 11
1 CREATE FUNCTION greeting()2 RETURNS TEXT AS $$3 BEGIN4 RETURN 'hello world!';5 END;6 $$ LANGUAGE 'plpgsql';
Wednesday, November 9, 11
declarebegin select ... if ... then update ... else while ... loop ... end loop; end if; return ...;end;
Wednesday, November 9, 11
¿Cuántas funciones?Postgres: 2333
Lua: 135
Wednesday, November 9, 11
Ventajas
Wednesday, November 9, 11
Cacheo automáticode consultas
Wednesday, November 9, 11
Menos coordinación entre la BD y Ruby
O Java, Python, Perl, PHP, etc.
Wednesday, November 9, 11
Encapsulación del esquema
Stored Procedures
Esquema Ruby
Wednesday, November 9, 11
Toda la lógica de negocios en SQL
Wednesday, November 9, 11
Wednesday, November 9, 11
No hagan eso por favor
Wednesday, November 9, 11
Squirm
github.com/bvision/squirm
Wednesday, November 9, 11
Squirm
• Azúcar sintáctico para la gema "pg"
• Connection pool básico
• Stored procedures como procs o lambdas
Wednesday, November 9, 11
1 Squirm.connect host: "localhost"2 Squirm.transaction do3 Squirm.exec "SELECT ..." do |result|4 result.to_a5 end6 Squirm.rollback7 end
Wednesday, November 9, 11
1 Squirm do2 connect host: "localhost"3 transaction do4 exec "SELECT ..." do |result|5 result.to_a6 end7 rollback8 end9 end
Wednesday, November 9, 11
1 Squirm do2 exec "CREATE FUNCTION ..."3 proc = procedure "greeting"4 proc.call "Juan"5 #=> "¡hola Juan!"6 end
Wednesday, November 9, 11
1 class Foo 2 3 @@bar = Procedure.load "bar" 4 5 def bar(*args) 6 @@bar.call(*args) 7 end 8 end 9 10 foo = Foo.new11 foo.bar("hello")
Wednesday, November 9, 11
GET followers/idsGET friends/idsGET lists/allGET favorites GET statuses/home_timelineGET statuses/mentionsGET statuses/user_timelineGET direct_messages
Wednesday, November 9, 11
SELECT followers.ids()SELECT friends.ids()SELECT lists.all()SELECT favorites() SELECT statuses.home_timeline()SELECT statuses.mentions()SELECT statuses.user_timeline()SELECT direct_messages()
Wednesday, November 9, 11
Squirm Model
github.com/bvision/squirm_model
Wednesday, November 9, 11
Squirm Model
• Generador de tablas, procedures
• SQL "scaffolding"
• Active Model
Wednesday, November 9, 11
$ squirm table person id email birth_date access_time bio
1 CREATE TABLE "person" (2 "id" SERIAL NOT NULL PRIMARY KEY,3 "email" VARCHAR(64) NOT NULL UNIQUE,4 "birth_date" DATE,5 "access_time" TIMESTAMP WITH TIME ZONE,6 "bio" TEXT7 );
Wednesday, November 9, 11
$ squirm table person id created_at
1 CREATE TABLE "person" ( 2 "id" SERIAL NOT NULL PRIMARY KEY, 3 "created_at" TIMESTAMP WITH TIME ZONE NOT NULL 4 ); 5 6 CREATE OR REPLACE FUNCTION "update_person_created_at_timestamp"() 7 RETURNS TRIGGER AS $$ 8 BEGIN 9 NEW.created_at = NOW();10 RETURN NEW;11 END;12 $$ LANGUAGE 'plpgsql';13 14 CREATE TRIGGER "update_person_created_at_timestamp"15 BEFORE INSERT ON "person"16 FOR EACH ROW EXECUTE PROCEDURE "update_person_created_at_timestamp"();
Wednesday, November 9, 11
$ squirm table person id email --api
CREATE TABLE "person" ...CREATE SCHEMA "person" ...CREATE FUNCTION "person.get" ...CREATE FUNCTION "person.create" ...CREATE FUNCTION "person.update" ...CREATE FUNCTION "person.delete" ...
Wednesday, November 9, 11
1 class Person 2 extend Squirm::Model ... 3 validates_presence_of :name 4 end 5 6 Person.create(...) 7 @person = Person.find(1) 8 @person.valid? 9 @person.to_json10 redirect_to @person
Wednesday, November 9, 11
1 class Person 2 extend Squirm::Model 3 4 sample do |s| 5 s.id = 1 6 s.name = "Juan Fulano" 7 end 8 9 validates_presence_of :name10 end
Wednesday, November 9, 11
1 class PersonTest < Test::Unit::TestCase2 def test_create3 assert Person.create(Person.sample)4 end5 end
Wednesday, November 9, 11
1 Squirm do 2 connect host: "localhost" 3 4 exec Person.to_ddl 5 6 Person.finalize 7 8 p = Person.create name: "John" 9 p.update name: "Johnny"10 p.delete11 end
Wednesday, November 9, 11
ROFLSCALE
0 7.5 15 22.5 30
Squirm Model ActiveRecord
Benchmarks
Wednesday, November 9, 11
¿Por qué no usar un ORM?
Wednesday, November 9, 11
Usen los ORM
• Active Record
• DataMapper
• Sequel
• otros
Wednesday, November 9, 11
Pero conozcan sus defectos
Wednesday, November 9, 11
Exhibition.all( :run_time.gt => 2, :run_time.lt => 5)
run_time > 1 AND run_time < 5
...you might be wondering how we can specify conditions beyond equality without resorting to SQL. Well, thanks to some clever additions to the Symbol class, it’s easy!
Wednesday, November 9, 11
table = Product.arel_tableProduct.where( table[:price].eq(2.99). or(table[:name].matches("%foo"))).to_sql
#=> "WHERE price = 2.99 OR name LIKE '%foo'"
railscasts.com/episodes/215-advanced-queries-in-rails-3
Wednesday, November 9, 11
SQL (mal) generado
Wednesday, November 9, 11
La abstracción dificulta el uso de features
avanzados
Wednesday, November 9, 11
Los stored procedures ofrecen una alternativa
interesante
Wednesday, November 9, 11
"Pensemos diferente"
Wednesday, November 9, 11
Nihil sub sole novum
Wednesday, November 9, 11
Postgres y MySQL están muy desaprovechados
Wednesday, November 9, 11
No usemos abstracciones innecesarias
Wednesday, November 9, 11
¡Gracias!
Wednesday, November 9, 11
Wednesday, November 9, 11
Obelisco: flickr.com/photos/budgetplaces/4173902613/Matz: flickr.com/photos/rrrodrigo/2394122680/
Gracias, fotógrafos
Wednesday, November 9, 11