Бази от данни и ORM
„ Програмиране с Python“, ФМИ
SELECT *
FROM lecturers
WHERE name IN ("Стефан Кънев", "Николай Бачийски", "Точо Точев", "Димитър Димитров")
13.05.2009
Persistency
- Нужда от трайно съхранение на информация
- Съхранение на (в някои случаи много) големи обеми
- Бърза обработка на конкретни подмножества от данни
- Усложняване на задачите по съхранение и обработка — нужда от абстракция, логическо и физическо разделение на ролите
DBMS & RDBMS
- Бази от данни (БД)
- Системи за управление на базите от данни (СУБД, СУРБД)
- СУБД — отделен, фонов, демонизиран процес
- Популярни: PostgreSQL, MySQL, SQLite, Oracle, BDB, MS SQL, …
Организация на данните
- Табличен формат (таблица, релация)
- Колони (полета, fields)
- Редове (rows, tuples, кортежи :)
Таблични данни
Комуникация със СУБД
- Може да работи на една и съща машина с ползвателя, но не е задължително
- Комуникация: през сокет (TCP или Unix socket)
- На ниско ниво: обикновено собствен двоичен протокол
Операции
- CRUD: create, retrieve, update, delete
- Интерфейс, който ни дава възможност да си говорим с базата от данни
- „Интерфейсен“ език: SQL
- Стандарт: ANSI SQL (да, ама не?)
SQL
- Structured Query Language
- Език със синтаксис, близък до естествения английски
-
ИЗБЕРИ име, фамилия, телефон ОТ потребители КЪДЕТО град = 'Пловдив'
-
SELECT name, surname, phone FROM users WHERE town = 'Пловдив'
DDL & DML
- DDL: data definition language
- Зависи доста от използваната СУБД
- DML: data modification language
- CRUD-операции по данните: INSERT, SELECT, UPDATE, DELETE
DDL
CREATE DATABASE demo;
CREATE TABLE Users (...);
ALTER TABLE Users CHARSET=utf8;
ALTER TABLE Users ADD COLUMN email VARCHAR(200) NOT NULL DEFAULT '';
DROP TABLE Users;
DDL (2)
- Разлики спрямо различните СУБД
- Налага се да се пише по-рядко, по-лесно се забравя :)
- Доста еднообразен => програми-помощници за DDL
DML: вмъкване
INSERT INTO sometable (some, fields)
VALUES (1, 22), (73, 321), (NULL, 13), (32, 102)
DML: извличане
SELECT some, fields
FROM sometable
WHERE fields > 10 AND (some IS NULL OR some = 42)
ORDER BY fields DESC
LIMIT 20;
DML: обновление
UPDATE sometable SET fields = fields + 10;
UPDATE sometable SET some = -1 WHERE some IS NULL;
UPDATE sometable SET fields = 1000 + fields, some = 200 + some WHERE fields > 42;
DML: изтриване
DELETE FROM sometable WHERE fields <= 42;
DELETE FROM sometable WHERE some IS NULL OR fields = 17;
Обемни бази данни
- Индекси: index, unique, fulltext
- Първичен ключ (индекс) (primary key)
- Външни ключове (foreign keys)
Пример
Countries:
id name town_id
-- ---- ----------
1 BG 1
2 UK 5
3 RUS 6
Towns:
id name country_id
-- ------- ----------
1 Sofia 1
2 Plovdiv 1
3 Varna 1
4 Burgas 1
5 London 2
6 Moscow 3
FK и взаимовръзки
-
SELECT name FROM towns WHERE country_id = 1;
-
SELECT t.name FROM towns t JOIN countries c ON c.id = t.country_id WHERE c.name = 'BG'
-
SELECT c.id, c.name AS country, t.name AS capital FROM countries c LEFT JOIN towns t ON t.id = c.capital_id;
-
JOIN
работи и с UPDATE и DELETE
(Де)нормализация
- Нормални форми на релационните БД
-
JOIN
и скорост на извличане
- Умишлена денормализация с цел оптимизация
- Всичко с мярката си
ORM
- Object-Relational Mapper
- Още едно (полезно) ниво на абстракция
- Съпоставя обекти от вашия програмен език на релации от вашата база
- М-то в MVC
- Пример: на таблицата „users“ от вашата БД съответства класът
User
ORM тук и там
- ActiveRecord в RoR
- SQLAlchemy (Django) за пайтън
- Microsoft LINQ: language integrated queries
- Dejavu и пайтън
Dejavu
- Units — модели, съответстващи на релация от БД
- Вашите класове-модели наследяват от
dejavu.Unit
-
class User(dejavu.Unit): pass
Примери
stefan = User(user = "skanev", name = "Стефан Кънев")
# box идва отнякъде
box.memorize(stefan)
print(stefan.id)
Още примери
active_admins = box.recall(User,
lambda user: user.is_admin and user.enabled)
for admin in active_admins: print(admin.email)
Пример
import dejavu
class Zoo(dejavu.Unit):
Name = dejavu.UnitProperty()
Size = dejavu.UnitProperty(int)
def total_legs(self):
return sum([x.Legs for x in self.Animal()])
class Animal(dejavu.Unit):
Legs = dejavu.UnitProperty(int, default=4)
Animal.set_properties({"Name": unicode, "ZooID": int})
Animal.many_to_one('ZooID', Zoo, 'ID')
arena = dejavu.Arena() # Set up a global Arena object.
conf = {'Connect': r"PROVIDER=MICROSOFT.JET.OLEDB.4.0;DATA SOURCE=C:\zookeeper.mdb;"}
arena.add_store("main", "access", conf)
arena.register_all(globals())