Object-Relational Mapper
Что такое Pony ORM?
Что такое Pony ORM?
• Объектно-реляционный маппер
• Реализует паттерн Identity Map
• Транслирует генераторы в SQL
• Включа...
Демо (15 минут)
• Редактор ER диаграмм
• Создание БД и заполнение данными
• Работа с данными в интерактивном
режиме
Pony ORM:
select(p for p in Person
if p.name.startswith('A') and p.tel is None
or p.dob.year < 2012
)
Способы построения з...
Способы построения запроса
Django:
Person.objects.filter(
Q(name__startswith('A'), tel__isnull=True)
| Q(dob__year__lt=201...
Способы построения запроса
SQLAlchemy:
session.query(Person).filter(
(Person.name.startswith('A')
& (Person.tel == None))
...
select(p for p in Person
if p.name.startswith('A') and p.tel is None
or p.dob.year < 2012
)
Person.objects.filter(
Q(name_...
Преимущества использования
синтаксиса генераторов:
• Несколько проще для запоминания
• Сложные запросы пишутся с меньшим
к...
Как Pony ORM транслирует
питоновские генераторы в SQL?
Трансляция генератора в SQL
1. Декомпиляция байткода,
восстановление абстрактного
синтаксического дерева (AST)
2. Трансляц...
Трансляция генератора в SQL
1. Декомпиляция байткода,
восстановление абстрактного
синтаксического дерева (AST)
2. Трансляц...
Декомпиляция байткода
• Используем паттерн Visitor
• Методы визитора соответствуют
операциям байткода
• Храним фрагменты в...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
COMPARE_OP...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
COMPARE_OP...
Декомпиляция байткода
(a + b.c) in x.y
> LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
COMPARE_...
Декомпиляция байткода
(a + b.c) in x.y
> LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
COMPARE_...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
> LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
COMPARE_...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
> LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
COMPARE_...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
> LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
COMPARE_...
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
> LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
COMPARE_OP in
Стек
Getattr(Nam...
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
> BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
COMPARE_OP in
Стек
Getattr(Nam...
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
> BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
COMPARE_OP in
Стек
Add(Name('a...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
> LOAD_FAST x
LOAD_ATTR y
COMPARE_...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
> LOAD_FAST x
LOAD_ATTR y
COMPARE_...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
> LOAD_ATTR y
COMPARE_...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
> LOAD_ATTR y
COMPARE_...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
> COMPARE_...
Декомпиляция байткода
(a + b.c) in x.y
LOAD_GLOBAL a
LOAD_FAST b
LOAD_ATTR c
BINARY_ADD
LOAD_FAST x
LOAD_ATTR y
> COMPARE_...
Абстрактное синтаксич. дерево (AST)
a
in
+
.c
b
.y
x
(a + b.c) in x.y
Трансляция генератора в SQL
1. Декомпиляция байткода,
восстановление абстрактного
синтаксического дерева (AST)
2. Трансляц...
Трансляция AST
• Используем паттерн Visitor
• Выполняем обход дерева вглубь
• Обрабатываем каждый узел на выходе
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
a
in
+
.c
b
.y
x
(a + b.c) in x.y
Трансляция AST
a
in
+
.c
b
.y
x
(a + b.c) in x.y
Трансляция AST
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
• В какой SQL должно транслироваться?
• Зависит от типов переменных
• “+” может означать сложение чисел или
конкатенацию с...
• (? + “b”.“c”) IN (SELECT …)
• CONCAT(?, “b”.“c”) IN (SELECT …)
• “x”.“y” LIKE ‘%’ || ? || “b”.“c” || ‘%’
(a + b.c) in x....
• Трансляция операции, такой как “+”, “in”
или взятие атрибута, зависит от смысла
подчиненных выражений
• Если класс транс...
• Инкапсулируют в себе результат
анализа AST
• Умеют генерировать результат
трансляции – “абстрактный SQL”
• Умеют комбини...
• NumericParamMonad
• StringParamMonad
• ObjectIterMonad
• ObjectParamMonad
• NumericAttrMonad
• StringAttrMonad
• ObjectA...
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада
Трансляция AST
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада
Трансляция AST
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
Трансляция AST
монада
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада
Трансляция AST
монада
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада монада
Трансляция AST
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада монада
Трансляция AST
монада
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада монада
монада
Трансляция AST
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада монада
Трансляция AST
монада
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада монада монада
Трансляция AST
монада
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада монада монада
Трансляция AST
монада
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада монада монада
монада
Трансляция AST
монада
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада монада монада
монада
Трансляция AST
монада
монада
in
.y
x
+
a .c
b
(a + b.c) in x.y
монада монада монада
монада
монада
Трансляция AST
монада
монада
in
.y
x
+
a .c
b
Aбстрактный SQL
(a + b.c) in x.y
['LIKE', ['COLUMN', 't1', 'y'],
['CONCAT',
['VALUE', '%'], ['PARAM', 'p1'],
['COLUMN', 't...
Трансляция генератора в SQL
1. Декомпиляция байткода,
восстановление абстрактного
синтаксического дерева (AST)
2. Трансляц...
Другие особенности Pony ORM
Другие особенности Pony ORM
• Автоматическая оптимизация запросов
• Identity Map
• Решение проблемы N+1
• Оптимистические ...
Django ORM
s1 = Student.object.get(pk=123)
print s1, s1.group.id
s2 = Student.object.get(pk=456)
print s2, s2.group.id
• С...
Django ORM
s1 = Student.object.get(pk=123)
print s1, s1.group.id
s2 = Student.object.get(pk=456)
print s2, s2.group.id
Django ORM
s1 = Student.object.get(pk=123)
print s1, s1.group.id
s2 = Student.object.get(pk=456)
print s2, s2.group.id
Stu...
Django ORM
s1 = Student.object.get(pk=123)
print s1, s1.group.id
s2 = Student.object.get(pk=456)
print s2, s2.group.id
Stu...
Django ORM
s1 = Student.object.get(pk=123)
print s1, s1.group.id
s2 = Student.object.get(pk=456)
print s2, s2.group.id
Stu...
Django ORM
s1 = Student.object.get(pk=123)
print s1, s1.group.id
s2 = Student.object.get(pk=456)
print s2, s2.group.id
Stu...
Pony ORM
s1 = Student[123]
print s1, s1.group.id
s2 = Student[456]
print s2, s2.group.id
Pony ORM – сиды, IdentityMap
s1 = Student[123]
print s1, s1.group.id
s2 = Student[456]
print s2, s2.group.id
Student 123
G...
Pony ORM – сиды, IdentityMap
s1 = Student[123]
print s1, s1.group.id
s2 = Student[456]
print s2, s2.group.id
Student 123
G...
Pony ORM – сиды, IdentityMap
s1 = Student[123]
print s1, s1.group.id
s2 = Student[456]
print s2, s2.group.id
Student 123
G...
Pony ORM – сиды, IdentityMap
s1 = Student[123]
print s1, s1.group.id
s2 = Student[456]
print s2, s2.group.id
Student 123
S...
Pony ORM – сиды, IdentityMap
s1 = Student[123]
print s1, s1.group.id
s2 = Student[456]
print s2, s2.group.id
Student 123
S...
Решение проблемы N+1 query
orders = select(o for o in Order
if o.price > 1000)
for o in orders:
print o.total_price, o.cus...
Решение проблемы N+1 query
Order 1
Order 3
Order 4
Order 7
Order 9
Customer 1
Customer 4
Customer 7
Решение проблемы N+1 query
orders = select(o for o in Order
if o.price > 1000)
for o in orders:
print o.total_price, o.cus...
Решение проблемы N+1 query
Order 1
Order 3
Order 4
Order 7
Order 9
Customer 1
Customer 4
Customer 7
Django ORM - транзакции
def transfer_money(id1, id2, amount):
account1 = Account.objects.get(pk=id1)
if account1.amount < ...
Django ORM - транзакции
@transaction.atomic
def transfer_money(id1, id2, amount):
account1 = Account.objects.get(pk=id1)
i...
@transaction.atomic
def transfer_money(id1, id2, amount):
account1 = Account.objects.
select_for_update.get(pk=id1)
if ac...
Pony ORM - транзакции
@db_session
def transfer_money(id1, id2, amount):
account1 = Account[id1]
if account1.amount < amoun...
db_session
• Pony автоматически отслеживает какие
объекты были изменены
• В момент выхода из db_session, если не
возникло ...
Оптимистические транзакции
• Pony отслеживает какие атрибуты
пользователь читал а какие изменял
• Если объект не был забло...
Оптимистические транзакции
UPDATE Account
SET amount = :new_value
WHERE id = :id
AND amount = :old_value
Pony ORM - транзакции
@db_session
def transfer_money(id1, id2, amount):
account1 = Account.get_for_update(id=id1)
if accou...
Особенности Pony ORM
• Использование генераторов и лямбд
для формулирования запросов
• Автоматическая оптимизация запросов...
Заключение
• Сайт ponyorm.com
• Редактор editor.ponyorm.com
• Установка pip install pony==0.5-beta
Спасибо за внимание!
of 103

Pony ORM - маппер нового поколения (Алексей Малашкевич и Александр Козловский)

Алексей Малашкевич - Автор и разработчик Pony ORM / Pony ORM / Россия, Санкт-Петербург Александр Козловский - Автор и разработчик Pony ORM / Pony ORM / Россия, Санкт-Петербург Pony ORM - маппер, который позволяет работать с базой данных с помощью генераторных выражений языка Питон. С помощью такого подхода Pony позволяет формулировать очень компактные и понятные запросы, которые автоматически транслируются в оптимизированный SQL. Pony обладает графическим редактором ER диаграмм - удобным инструментом для создания и редактирования модели данных. В докладе разработчики Pony ORM расскажут про процесс перевода объектно-ориентированного запроса в запрос на языке SQL, о том какие оптимизации Pony применяет на каждом этапе обработки запроса, какие сложности стояли при разработке высокопроизводительного ORM и как Pony ORM облегчает и ускоряет разработку приложений. http://www.it-sobytie.ru/events/2040
Published on: Mar 4, 2016
Published in: Education      
Source: www.slideshare.net


Transcripts - Pony ORM - маппер нового поколения (Алексей Малашкевич и Александр Козловский)

  • 1. Object-Relational Mapper
  • 2. Что такое Pony ORM?
  • 3. Что такое Pony ORM? • Объектно-реляционный маппер • Реализует паттерн Identity Map • Транслирует генераторы в SQL • Включает редактор ER диаграмм • Автоматически оптимизирует SQL запросы • Поддерживает Python 2.5 – 2.7 • Скоро появится поддержка Python 3
  • 4. Демо (15 минут) • Редактор ER диаграмм • Создание БД и заполнение данными • Работа с данными в интерактивном режиме
  • 5. Pony ORM: select(p for p in Person if p.name.startswith('A') and p.tel is None or p.dob.year < 2012 ) Способы построения запроса
  • 6. Способы построения запроса Django: Person.objects.filter( Q(name__startswith('A'), tel__isnull=True) | Q(dob__year__lt=2012) )
  • 7. Способы построения запроса SQLAlchemy: session.query(Person).filter( (Person.name.startswith('A') & (Person.tel == None)) | (extract('year', Person.dob) < 2012) )
  • 8. select(p for p in Person if p.name.startswith('A') and p.tel is None or p.dob.year < 2012 ) Person.objects.filter( Q(name__startswith('A'), tel__isnull=True) | Q(dob__year__lt=2012) ) session.query(Person).filter( (Person.name.startswith('A') & (Person.tel == None)) | (extract('year', Person.dob) < 2012) )
  • 9. Преимущества использования синтаксиса генераторов: • Несколько проще для запоминания • Сложные запросы пишутся с меньшим количеством «наворотов» (типа “Q”) • Трансляция запросов в SQL осуществляется гораздо быстрее! (можно кешировать результат трансляции и использовать объект кода генератора как ключ)
  • 10. Как Pony ORM транслирует питоновские генераторы в SQL?
  • 11. Трансляция генератора в SQL 1. Декомпиляция байткода, восстановление абстрактного синтаксического дерева (AST) 2. Трансляция AST в “абстрактный SQL” (представленный в виде списков) 3. Трансляция “абстрактного SQL” в конкретный диалект языка SQL
  • 12. Трансляция генератора в SQL 1. Декомпиляция байткода, восстановление абстрактного синтаксического дерева (AST) 2. Трансляция AST в “абстрактный SQL” (представленный в виде списков) 3. Трансляция “абстрактного SQL” в конкретный диалект языка SQL
  • 13. Декомпиляция байткода • Используем паттерн Visitor • Методы визитора соответствуют операциям байткода • Храним фрагменты восстановленного AST на стеке • Каждый метод или помещает на вершину стека новый фрагмент AST, или комбинирует имеющиеся фрагменты
  • 14. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c BINARY_ADD LOAD_FAST x LOAD_ATTR y COMPARE_OP in
  • 15. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c BINARY_ADD LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек
  • 16. Декомпиляция байткода (a + b.c) in x.y > LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c BINARY_ADD LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек
  • 17. Декомпиляция байткода (a + b.c) in x.y > LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c BINARY_ADD LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек Name('a')
  • 18. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a > LOAD_FAST b LOAD_ATTR c BINARY_ADD LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек Name('a')
  • 19. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a > LOAD_FAST b LOAD_ATTR c BINARY_ADD LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек Name('b') Name('a')
  • 20. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b > LOAD_ATTR c BINARY_ADD LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек Name('b') Name('a')
  • 21. (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b > LOAD_ATTR c BINARY_ADD LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек Getattr(Name('b'), 'c') Name('a') Декомпиляция байткода
  • 22. (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c > BINARY_ADD LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек Getattr(Name('b'), 'c') Name('a') Декомпиляция байткода
  • 23. (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c > BINARY_ADD LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек Add(Name('a'), Getattr(Name('b'), 'c')) Декомпиляция байткода
  • 24. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c BINARY_ADD > LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек Add(Name('a'), Getattr(Name('b'), 'c'))
  • 25. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c BINARY_ADD > LOAD_FAST x LOAD_ATTR y COMPARE_OP in Стек Name('x') Add(Name('a'), Getattr(Name('b'), 'c'))
  • 26. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c BINARY_ADD LOAD_FAST x > LOAD_ATTR y COMPARE_OP in Стек Name('x') Add(Name('a'), Getattr(Name('b'), 'c'))
  • 27. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c BINARY_ADD LOAD_FAST x > LOAD_ATTR y COMPARE_OP in Стек Getattr(Name('x'), 'y') Add(Name('a'), Getattr(Name('b'), 'c'))
  • 28. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c BINARY_ADD LOAD_FAST x LOAD_ATTR y > COMPARE_OP in Стек Getattr(Name('x'), 'y') Add(Name('a'), Getattr(Name('b'), 'c'))
  • 29. Декомпиляция байткода (a + b.c) in x.y LOAD_GLOBAL a LOAD_FAST b LOAD_ATTR c BINARY_ADD LOAD_FAST x LOAD_ATTR y > COMPARE_OP in Стек Compare('in', Add(…), Getattr(…))
  • 30. Абстрактное синтаксич. дерево (AST) a in + .c b .y x (a + b.c) in x.y
  • 31. Трансляция генератора в SQL 1. Декомпиляция байткода, восстановление абстрактного синтаксического дерева (AST) 2. Трансляция AST в “абстрактный SQL” (представленный в виде списков) 3. Трансляция “абстрактного SQL” в конкретный диалект языка SQL
  • 32. Трансляция AST • Используем паттерн Visitor • Выполняем обход дерева вглубь • Обрабатываем каждый узел на выходе
  • 33. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 34. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 35. a in + .c b .y x (a + b.c) in x.y Трансляция AST
  • 36. a in + .c b .y x (a + b.c) in x.y Трансляция AST
  • 37. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 38. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 39. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 40. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 41. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 42. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 43. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 44. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 45. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 46. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 47. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 48. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 49. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 50. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 51. • В какой SQL должно транслироваться? • Зависит от типов переменных • “+” может означать сложение чисел или конкатенацию строк – транслируется в +, CONCAT или || • “in” может транслироваться в подзапрос или в LIKE (a + b.c) in x.y Трансляция AST
  • 52. • (? + “b”.“c”) IN (SELECT …) • CONCAT(?, “b”.“c”) IN (SELECT …) • “x”.“y” LIKE ‘%’ || ? || “b”.“c” || ‘%’ (a + b.c) in x.y Трансляция AST
  • 53. • Трансляция операции, такой как “+”, “in” или взятие атрибута, зависит от смысла подчиненных выражений • Если класс транслятора сам выполняет весь необходимый анализ, логика транслятора становится чрезмерно сложной • На помощь приходят монады (a + b.c) in x.y Трансляция AST
  • 54. • Инкапсулируют в себе результат анализа AST • Умеют генерировать результат трансляции – “абстрактный SQL” • Умеют комбинировать себя с другими монадами • Обрабатывая узел AST, транслятор дает команду монадам нижележащих узлов скомбинировать себя и получить новую монаду Монады
  • 55. • NumericParamMonad • StringParamMonad • ObjectIterMonad • ObjectParamMonad • NumericAttrMonad • StringAttrMonad • ObjectAttrMonad • FuncMonad • и т.д. … Монады
  • 56. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 57. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 58. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  • 59. (a + b.c) in x.y монада Трансляция AST in .y x + a .c b
  • 60. (a + b.c) in x.y монада Трансляция AST in .y x + a .c b
  • 61. (a + b.c) in x.y монада Трансляция AST in .y x + a .c b
  • 62. (a + b.c) in x.y монада Трансляция AST монада in .y x + a .c b
  • 63. (a + b.c) in x.y Трансляция AST монада монада in .y x + a .c b
  • 64. (a + b.c) in x.y монада Трансляция AST монада монада in .y x + a .c b
  • 65. (a + b.c) in x.y монада монада Трансляция AST монада in .y x + a .c b
  • 66. (a + b.c) in x.y монада монада Трансляция AST монада монада in .y x + a .c b
  • 67. (a + b.c) in x.y монада монада монада Трансляция AST монада in .y x + a .c b
  • 68. (a + b.c) in x.y монада монада Трансляция AST монада монада in .y x + a .c b
  • 69. (a + b.c) in x.y монада монада монада Трансляция AST монада монада in .y x + a .c b
  • 70. (a + b.c) in x.y монада монада монада Трансляция AST монада монада in .y x + a .c b
  • 71. (a + b.c) in x.y монада монада монада монада Трансляция AST монада монада in .y x + a .c b
  • 72. (a + b.c) in x.y монада монада монада монада Трансляция AST монада монада in .y x + a .c b
  • 73. (a + b.c) in x.y монада монада монада монада монада Трансляция AST монада монада in .y x + a .c b
  • 74. Aбстрактный SQL (a + b.c) in x.y ['LIKE', ['COLUMN', 't1', 'y'], ['CONCAT', ['VALUE', '%'], ['PARAM', 'p1'], ['COLUMN', 't2', 'c'], ['VALUE', '%'] ] ] - Позволяет абстрагироваться от специфики конкретного диалекта
  • 75. Трансляция генератора в SQL 1. Декомпиляция байткода, восстановление абстрактного синтаксического дерева (AST) 2. Трансляция AST в “абстрактный SQL” (представленный в виде списков) 3. Трансляция “абстрактного SQL” в конкретный диалект языка SQL
  • 76. Другие особенности Pony ORM
  • 77. Другие особенности Pony ORM • Автоматическая оптимизация запросов • Identity Map • Решение проблемы N+1 • Оптимистические транзакции
  • 78. Django ORM s1 = Student.object.get(pk=123) print s1, s1.group.id s2 = Student.object.get(pk=456) print s2, s2.group.id • Сколько SQL-запросов выполнится? • Сколько объектов будет создано?
  • 79. Django ORM s1 = Student.object.get(pk=123) print s1, s1.group.id s2 = Student.object.get(pk=456) print s2, s2.group.id
  • 80. Django ORM s1 = Student.object.get(pk=123) print s1, s1.group.id s2 = Student.object.get(pk=456) print s2, s2.group.id Student 123
  • 81. Django ORM s1 = Student.object.get(pk=123) print s1, s1.group.id s2 = Student.object.get(pk=456) print s2, s2.group.id Student 123 Group 1
  • 82. Django ORM s1 = Student.object.get(pk=123) print s1, s1.group.id s2 = Student.object.get(pk=456) print s2, s2.group.id Student 123 Student 456 Group 1
  • 83. Django ORM s1 = Student.object.get(pk=123) print s1, s1.group.id s2 = Student.object.get(pk=456) print s2, s2.group.id Student 123 Student 456 Group 1 Group 1
  • 84. Pony ORM s1 = Student[123] print s1, s1.group.id s2 = Student[456] print s2, s2.group.id
  • 85. Pony ORM – сиды, IdentityMap s1 = Student[123] print s1, s1.group.id s2 = Student[456] print s2, s2.group.id Student 123 Group 1
  • 86. Pony ORM – сиды, IdentityMap s1 = Student[123] print s1, s1.group.id s2 = Student[456] print s2, s2.group.id Student 123 Group 1 сид (seed)
  • 87. Pony ORM – сиды, IdentityMap s1 = Student[123] print s1, s1.group.id s2 = Student[456] print s2, s2.group.id Student 123 Group 1 сид (seed)
  • 88. Pony ORM – сиды, IdentityMap s1 = Student[123] print s1, s1.group.id s2 = Student[456] print s2, s2.group.id Student 123 Student 456 Group 1 сид (seed)
  • 89. Pony ORM – сиды, IdentityMap s1 = Student[123] print s1, s1.group.id s2 = Student[456] print s2, s2.group.id Student 123 Student 456 Group 1 сид (seed)
  • 90. Решение проблемы N+1 query orders = select(o for o in Order if o.price > 1000) for o in orders: print o.total_price, o.customer.name SELECT o.id, o.total_price, o.customer_id, … FROM “Order” o WHERE o.price > 1000
  • 91. Решение проблемы N+1 query Order 1 Order 3 Order 4 Order 7 Order 9 Customer 1 Customer 4 Customer 7
  • 92. Решение проблемы N+1 query orders = select(o for o in Order if o.price > 1000) for o in orders: print o.total_price, o.customer.name SELECT c.id, c.name, … FROM “Customer” c WHERE c.id IN (?, ?, ?)
  • 93. Решение проблемы N+1 query Order 1 Order 3 Order 4 Order 7 Order 9 Customer 1 Customer 4 Customer 7
  • 94. Django ORM - транзакции def transfer_money(id1, id2, amount): account1 = Account.objects.get(pk=id1) if account1.amount < amount: raise ValueError(‘Not enough money!’) account2 = Account.object.get(pk=id2) account1.amount -= amount account1.save() account2.amount += amount account2.save()
  • 95. Django ORM - транзакции @transaction.atomic def transfer_money(id1, id2, amount): account1 = Account.objects.get(pk=id1) if account1.amount < amount: raise ValueError(‘Not enough money!’) account2 = Account.object.get(pk=id2) account1.amount -= amount account1.save() account2.amount += amount account2.save()
  • 96. @transaction.atomic def transfer_money(id1, id2, amount): account1 = Account.objects. select_for_update.get(pk=id1) if account1.amount < amount: raise ValueError(‘Not enough money!’) account2 = Account.objects. select_for_update.get(pk=id2) account1.amount -= amount account1.save() account2.amount += amount account2.save()
  • 97. Pony ORM - транзакции @db_session def transfer_money(id1, id2, amount): account1 = Account[id1] if account1.amount < amount: raise ValueError(‘Not enough money!’) account1.amount -= amount Account[id2].amount += amount
  • 98. db_session • Pony автоматически отслеживает какие объекты были изменены • В момент выхода из db_session, если не возникло исключений, происходит сохранение всех измененных объектов в рамках единой транзакции • Пользователь не обязан сам вызывать save для сохранения объектов
  • 99. Оптимистические транзакции • Pony отслеживает какие атрибуты пользователь читал а какие изменял • Если объект не был заблокирован в БД в момент выборки, при сохранении объекта Pony автоматически добавляет проверки для оптимистических блокировок
  • 100. Оптимистические транзакции UPDATE Account SET amount = :new_value WHERE id = :id AND amount = :old_value
  • 101. Pony ORM - транзакции @db_session def transfer_money(id1, id2, amount): account1 = Account.get_for_update(id=id1) if account1.amount < amount: raise ValueError(‘Not enough money!’) account1.amount -= amount account2 = Account.get_for_update(id=id2) account2.amount += amount
  • 102. Особенности Pony ORM • Использование генераторов и лямбд для формулирования запросов • Автоматическая оптимизация запросов • Identity Map • Решение проблемы N+1 • Оптимистические транзакции • Графический редактор ER-диаграмм • В перспективе – поддержка NoSQL
  • 103. Заключение • Сайт ponyorm.com • Редактор editor.ponyorm.com • Установка pip install pony==0.5-beta Спасибо за внимание!