Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
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
Спасибо за внимание!
Nächste SlideShare
Wird geladen in …5
×

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

973 Aufrufe

Veröffentlicht am

Алексей Малашкевич - Автор и разработчик 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

Veröffentlicht in: Bildung
  • Als Erste(r) kommentieren

  • Gehören Sie zu den Ersten, denen das gefällt!

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

  1. 1. Object-Relational Mapper
  2. 2. Что такое Pony ORM?
  3. 3. Что такое Pony ORM? • Объектно-реляционный маппер • Реализует паттерн Identity Map • Транслирует генераторы в SQL • Включает редактор ER диаграмм • Автоматически оптимизирует SQL запросы • Поддерживает Python 2.5 – 2.7 • Скоро появится поддержка Python 3
  4. 4. Демо (15 минут) • Редактор ER диаграмм • Создание БД и заполнение данными • Работа с данными в интерактивном режиме
  5. 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. 6. Способы построения запроса Django: Person.objects.filter( Q(name__startswith('A'), tel__isnull=True) | Q(dob__year__lt=2012) )
  7. 7. Способы построения запроса SQLAlchemy: session.query(Person).filter( (Person.name.startswith('A') & (Person.tel == None)) | (extract('year', Person.dob) < 2012) )
  8. 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. 9. Преимущества использования синтаксиса генераторов: • Несколько проще для запоминания • Сложные запросы пишутся с меньшим количеством «наворотов» (типа “Q”) • Трансляция запросов в SQL осуществляется гораздо быстрее! (можно кешировать результат трансляции и использовать объект кода генератора как ключ)
  10. 10. Как Pony ORM транслирует питоновские генераторы в SQL?
  11. 11. Трансляция генератора в SQL 1. Декомпиляция байткода, восстановление абстрактного синтаксического дерева (AST) 2. Трансляция AST в “абстрактный SQL” (представленный в виде списков) 3. Трансляция “абстрактного SQL” в конкретный диалект языка SQL
  12. 12. Трансляция генератора в SQL 1. Декомпиляция байткода, восстановление абстрактного синтаксического дерева (AST) 2. Трансляция AST в “абстрактный SQL” (представленный в виде списков) 3. Трансляция “абстрактного SQL” в конкретный диалект языка SQL
  13. 13. Декомпиляция байткода • Используем паттерн Visitor • Методы визитора соответствуют операциям байткода • Храним фрагменты восстановленного AST на стеке • Каждый метод или помещает на вершину стека новый фрагмент AST, или комбинирует имеющиеся фрагменты
  14. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 30. Абстрактное синтаксич. дерево (AST) a in + .c b .y x (a + b.c) in x.y
  31. 31. Трансляция генератора в SQL 1. Декомпиляция байткода, восстановление абстрактного синтаксического дерева (AST) 2. Трансляция AST в “абстрактный SQL” (представленный в виде списков) 3. Трансляция “абстрактного SQL” в конкретный диалект языка SQL
  32. 32. Трансляция AST • Используем паттерн Visitor • Выполняем обход дерева вглубь • Обрабатываем каждый узел на выходе
  33. 33. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  34. 34. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  35. 35. a in + .c b .y x (a + b.c) in x.y Трансляция AST
  36. 36. a in + .c b .y x (a + b.c) in x.y Трансляция AST
  37. 37. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  38. 38. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  39. 39. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  40. 40. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  41. 41. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  42. 42. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  43. 43. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  44. 44. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  45. 45. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  46. 46. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  47. 47. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  48. 48. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  49. 49. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  50. 50. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  51. 51. • В какой SQL должно транслироваться? • Зависит от типов переменных • “+” может означать сложение чисел или конкатенацию строк – транслируется в +, CONCAT или || • “in” может транслироваться в подзапрос или в LIKE (a + b.c) in x.y Трансляция AST
  52. 52. • (? + “b”.“c”) IN (SELECT …) • CONCAT(?, “b”.“c”) IN (SELECT …) • “x”.“y” LIKE ‘%’ || ? || “b”.“c” || ‘%’ (a + b.c) in x.y Трансляция AST
  53. 53. • Трансляция операции, такой как “+”, “in” или взятие атрибута, зависит от смысла подчиненных выражений • Если класс транслятора сам выполняет весь необходимый анализ, логика транслятора становится чрезмерно сложной • На помощь приходят монады (a + b.c) in x.y Трансляция AST
  54. 54. • Инкапсулируют в себе результат анализа AST • Умеют генерировать результат трансляции – “абстрактный SQL” • Умеют комбинировать себя с другими монадами • Обрабатывая узел AST, транслятор дает команду монадам нижележащих узлов скомбинировать себя и получить новую монаду Монады
  55. 55. • NumericParamMonad • StringParamMonad • ObjectIterMonad • ObjectParamMonad • NumericAttrMonad • StringAttrMonad • ObjectAttrMonad • FuncMonad • и т.д. … Монады
  56. 56. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  57. 57. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  58. 58. (a + b.c) in x.y Трансляция AST in .y x + a .c b
  59. 59. (a + b.c) in x.y монада Трансляция AST in .y x + a .c b
  60. 60. (a + b.c) in x.y монада Трансляция AST in .y x + a .c b
  61. 61. (a + b.c) in x.y монада Трансляция AST in .y x + a .c b
  62. 62. (a + b.c) in x.y монада Трансляция AST монада in .y x + a .c b
  63. 63. (a + b.c) in x.y Трансляция AST монада монада in .y x + a .c b
  64. 64. (a + b.c) in x.y монада Трансляция AST монада монада in .y x + a .c b
  65. 65. (a + b.c) in x.y монада монада Трансляция AST монада in .y x + a .c b
  66. 66. (a + b.c) in x.y монада монада Трансляция AST монада монада in .y x + a .c b
  67. 67. (a + b.c) in x.y монада монада монада Трансляция AST монада in .y x + a .c b
  68. 68. (a + b.c) in x.y монада монада Трансляция AST монада монада in .y x + a .c b
  69. 69. (a + b.c) in x.y монада монада монада Трансляция AST монада монада in .y x + a .c b
  70. 70. (a + b.c) in x.y монада монада монада Трансляция AST монада монада in .y x + a .c b
  71. 71. (a + b.c) in x.y монада монада монада монада Трансляция AST монада монада in .y x + a .c b
  72. 72. (a + b.c) in x.y монада монада монада монада Трансляция AST монада монада in .y x + a .c b
  73. 73. (a + b.c) in x.y монада монада монада монада монада Трансляция AST монада монада in .y x + a .c b
  74. 74. Aбстрактный SQL (a + b.c) in x.y ['LIKE', ['COLUMN', 't1', 'y'], ['CONCAT', ['VALUE', '%'], ['PARAM', 'p1'], ['COLUMN', 't2', 'c'], ['VALUE', '%'] ] ] - Позволяет абстрагироваться от специфики конкретного диалекта
  75. 75. Трансляция генератора в SQL 1. Декомпиляция байткода, восстановление абстрактного синтаксического дерева (AST) 2. Трансляция AST в “абстрактный SQL” (представленный в виде списков) 3. Трансляция “абстрактного SQL” в конкретный диалект языка SQL
  76. 76. Другие особенности Pony ORM
  77. 77. Другие особенности Pony ORM • Автоматическая оптимизация запросов • Identity Map • Решение проблемы N+1 • Оптимистические транзакции
  78. 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. 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. 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. 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. 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. 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. 84. Pony ORM s1 = Student[123] print s1, s1.group.id s2 = Student[456] print s2, s2.group.id
  85. 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. 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. 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. 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. 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. 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. 91. Решение проблемы N+1 query Order 1 Order 3 Order 4 Order 7 Order 9 Customer 1 Customer 4 Customer 7
  92. 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. 93. Решение проблемы N+1 query Order 1 Order 3 Order 4 Order 7 Order 9 Customer 1 Customer 4 Customer 7
  94. 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. 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. 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. 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. 98. db_session • Pony автоматически отслеживает какие объекты были изменены • В момент выхода из db_session, если не возникло исключений, происходит сохранение всех измененных объектов в рамках единой транзакции • Пользователь не обязан сам вызывать save для сохранения объектов
  99. 99. Оптимистические транзакции • Pony отслеживает какие атрибуты пользователь читал а какие изменял • Если объект не был заблокирован в БД в момент выборки, при сохранении объекта Pony автоматически добавляет проверки для оптимистических блокировок
  100. 100. Оптимистические транзакции UPDATE Account SET amount = :new_value WHERE id = :id AND amount = :old_value
  101. 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. 102. Особенности Pony ORM • Использование генераторов и лямбд для формулирования запросов • Автоматическая оптимизация запросов • Identity Map • Решение проблемы N+1 • Оптимистические транзакции • Графический редактор ER-диаграмм • В перспективе – поддержка NoSQL
  103. 103. Заключение • Сайт ponyorm.com • Редактор editor.ponyorm.com • Установка pip install pony==0.5-beta Спасибо за внимание!

×