Реляционный SQL по сравнению с NoSQL MONGODB
Когда мы сравниваем реляционную систему и NoSQL, один из самых важных факторов, который необходимо проанализировать - это механизмы доступа к данным. Как мы увидим в следующих нескольких статьях этой серии, язык SQL, используемый в системах управления реляционными базами данных, является намного более функциональным и мощным по сравнению с его конкурентом NoSQL. Данное утверждение является лишь оценкой, данной автором этим двум языкам доступа к системам, и мы не хотим склонить читателей к использованию реляционных систем.
Аббревиатура CRUD означает Create (создать), Read (прочитать), Update(обновить) и Delete (удалить). Это операции, используемые для добавления, поиска и выборки, управления и удаления данных, хранимых в системах управления базами данных. Для выполнения операций обмена данными реляционные базы данных используют крайне мощный, стандартный язык структурированных запросов - Structured Query Language (SQL).
Их конкуренты, NoSQL-системы, используют более простые языки и API-интерфейсы для хранения данных и доступа к ним. Большинство NoSQL-продуктов имеют уникальные языки и механизмы, которые обеспечивают CRUD-возможности. В данной статье при сравнении реляционных и NoSQL-систем, мы сопоставим операции SQL CRUD с методом доступа MongoDB. В наше обсуждение будет входить работа с данными, а также построение расширенных запросов, которые включают в себя соединения или их отсутствие. В следующей статье этой серии мы рассмотрим манипулирование данными и их удаление.
Реляционная SQL
Реляционный язык структурированных запросов или SQL - это язык, специально созданный для работы с данными, хранящимися в системах управления реляционными базами данных. В основе этого языка лежит алгебра - область математики, в которой символы используются для представления цифр или членов конкретных множеств. Символы представляют величины или общие функции членов множества. Множество объединяется с двоичными операциями, которые задаются для множества. Э.Ф. КОДД, отец систем управления реляционными базами данных, впервые описал реляционную алгебру в 1970 году.
Язык SQL можно дальше разложить на:
- Язык определения данных - Data Definition Language (DDL)
Используется для построения схем и связанных объектов хранения в системах управления базами данных - Язык манипулирования данными - Data Manipulation Language (DML)
Операторы, которые позволяют приложениям взаимодействовать с информацией базы данных – SELECT, INSERT, UPDATE, DELETE. Также известны как операции CRUD. - Язык управления данными - Data Control Language (DCL)
Операторы, используемые для управления безопасностью внутри базы данных. Определяют, кто и к чему имеет доступ.
На протяжении лет SQL является стандартным языком, используемым для работы с реляционными базами данных. Он был адаптирован в качестве стандартного языка различными организациями, включая Американский национальный институт стандартизации (ANSI) и Международную организацию по стандартизации, которая входит в Международную электротехническую комиссию (ISO-IEC).
Цель стандартизации - иметь возможность переносить язык из одной системы в другую. Он стал стандартным языком, используемым для работы со всеми системами управления реляционными базами данных (RDBMS). Поскольку все значительные RDBMS поддерживают язык SQL, разработчики и DBA могут легко использовать свои навыки при работе с различными реляционными базами данных. Нам следует использовать выражение "переносимый язык" несколько в более широком смысле, поскольку все разработчики баз данных предлагают улучшения языка, специфические для их продукции. Такие улучшения в большинстве случаев не могут быть перенесены между продуктами различных разработчиков.
Методы MongoDB
MongoDB предлагает методы и команды для администрирования сред баз данных и взаимодействия с хранящимися данными. Доступ к этим методам может быть получен из уровня абстракции и одним из их подклассов являются оберточные функционалы для команд или множества команд. В этой статье мы сосредоточимся на методах MongoDB, которые уровень приложений использует для взаимодействия с данными, хранящимися в базе данных MongoDB.
Перед тем, как начать наше сравнение формулировок запросов MongoDB и SQL, дадим несколько определений и дополнительных сравнений.
Реляционная (Oracle) |
NoSQL (MongoDB) |
Database (база данных) |
Database (база данных) |
Table (таблица) |
Collection (Сборник) |
Row (строка) |
Document (документ) |
Column (колонка) |
Field (поле) |
Index (индекс) |
Index (индекс) |
Primary Key (первичный ключ) |
_ID field |
Join (соединение) |
Reference or Embedded Document (указатель или встроенный документ) |
Check Constraint (проверочное ограничение) |
Validation Rules (правила проверки) |
Операция |
Реляционная (Oracle) |
Метод NoSQL (MongoDB) |
Данные запроса |
SELECT |
db.collection.FIND() - where collection is the name of the collection being searched |
Вставить данные |
INSERT |
db.collection.insertOne () – inserts single document db.collection.insertMany() – inserts multiple documents db.collection.insert() – inserts one or more documents |
Обновить данные |
UPDATE |
db.collection.updateOne() – updates single document db.collection.updateMany() – updates multiple documents db.collection.replaceOne() – replaces a single document db.collection.update() – updates one or more documents |
Удалить данные |
DELETE |
db.collection.deleteOne() – deletes single document db.collection.deleteMany() –deletes multiple documents db.collection.remove() – deletes one or more documents |
Термин |
Определение |
Projection (Проекция) |
Оператор, который ограничивает реляционные колонки или поля MongoDB, возвращенные по запросу. |
Selection (Выбор) |
Оператор, который ограничивает реляционные ряды или документы MongoDB, возвращенные по запросу. |
Cursor (курсор) |
Управляющая структура, которая позволяет приложению просматривать результаты, возвращенные по данному запросу. |
Давайте взглянем на примитивный запрос:
Реляционная система |
|
SELECT empno, ename |
Projection (Проекция) |
FROM hr. employees |
Schema Object (объект схемы) |
WHERE salary > 35000 |
Selection (Выбор) |
MongoDB |
|
db.employees.find( |
Schema Object (объект схемы) |
{ salary: {$gt: 35000 } } |
Selection (Выбор) |
{ empno: 1, ename: 1 } |
Projection (Проекция) |
Как Oracle так и MongoDB используют операции запросов, которые позволяют использовать простой и сложный выбор данных:
Оператор |
Oracle |
MongoDB |
Равно |
= |
$eq |
Больше, чем |
> |
$gt |
Больше или равный |
>= |
$gte |
Меньше, чем |
< |
$lt |
Меньше или равный |
<= |
$lte |
Не равный |
!= |
$ne |
Совпадает со значениями в массиве |
IN |
$in |
Не совпадает со значениями в массиве |
NOT IN |
$nin |
Условие совпадения с одним из операторов |
OR |
$or |
Условие совпадения с обоими операторами |
AND |
$and |
Не совпадает с запросным выражением |
NOT |
$not |
Не совпадает с обоими запросными выражениями |
NOT |
$nor |
Поиск шаблона строки |
LIKE |
$regex |
Отсутствие значения |
NULL |
NULL* |
Совпадение документа с конкретным полем |
N/A |
$exists |
Совпадение документа с конкретным типом |
N/A |
$type |
Я намеренно не описал все возможные операторы, поскольку обе базы данных имеют десятки возможных операторов. Oracle является безоговорочным победителем, когда дело касается размаха и глубины доступных операторов. В этой статье была поставлена цель провести общее сравнение механизмов доступа к данным в NoSQL-системе и реляционной системе, а не глубокий анализ синтаксиса SQL и NoSQL. В последней статье из серии по сравнению реляционной и NoSQL-системы я предоставлю более детальное сравнение.
Вот пример сортировки возвращенных результатов:
Реляционная система |
|
SELECT empno, ename, address |
Projection (Проекция) |
FROM hr. employees |
Schema Object (объект схемы) |
WHERE salary > 35000 |
Selection (Выбор) |
ORDER BY empno |
Результаты сортировки (используется ключевое слово DESC для убывания) |
MongoDB |
|
db.employees.find( |
Schema Object (объект схемы) |
{ salary: {$gt: 35000 } } |
Selection (Выбор) |
{ empno: 1, ename: 1 } ) |
Projection (Проекция) |
.sort ( { empno: 1 } ) |
Результаты сортировки (используется ключевое слово -1 для убывания) |
Реляционные соединения
Оператор соединения в языке SQL совмещает колонки из двух или более реляционных таблиц. Критерии, которые являются одинаковыми для обеих таблиц используются для установления связей между объектами. Для примера, давайте взглянем на таблицы "Сотрудники" и "Отдел".
Наша таблица "Сотрудники" содержит информацию о персонале, работающем в нашей условной организации. В таблице хранится идентификаторы номера сотрудника, имени, должности и отдела. Колонка DEPTNO в строке сотрудника содержит номер отдела, к которому закреплен сотрудник. Но могут быть и другие признаки, дающие дополнительное описание отдела, которое мы хотим хранить в нашей базе данных. Таблица "Отделы" содержит номер отдела, а также название отдела и его расположение.
Таблица "Сотрудники" |
|
EMPNO |
Идентификационный номер сотрудника |
ENAME |
Имя сотрудника |
JOBNO |
Номер должности сотрудника |
MGRNO |
Номер руководителя сотрудника |
DEPTNO |
Отдел, в котором работает сотрудник |
... |
Дополнительная информация о сотруднике |
Таблица "Отделы" |
|
DEPTNO |
Номер отдела |
DEPTNAME |
Название отдела |
DEPTLOC |
Расположение отдела |
… |
Дополнительная информация об отделе |
Когда мы хотим получить информацию о сотруднике из обеих таблиц, в языке SQL мы будем использовать оператор соединения, который позволяет соединить или объединить таблицы вместе. SQL поддерживает различные синтаксисы соединения. Вот некоторые самые распространенные операторы соединения:
- Inner Join – Объединение двух таблиц с помощью явно заданного оператора соединения. Возвращает данные на основании совпадения значений, содержащихся в колонках, указанных в операторе соединения.
- Left Outer Join – Объединение двух таблиц с помощью явно заданного оператора соединения, но также возвращает несовпадающие строки из первой таблицы.
- Right Outer Join – Объединение двух таблиц с помощью явно заданного оператора соединения, но также возвращает несовпадающие строки из второй таблицы.
Описанный ниже SQL-оператор делает выборку имен наших сотрудников и отделов, в которых они работают. Мы объединяем две таблицы вместе, используя колонку DEPTNO, которая является критерием, одинаковым для обеих таблиц. Информация из обеих таблиц будет возвращена в наше приложение, когда колонка DEPTNO из таблицы "Сотрудники" совпадет со значением из колонки DEPTNO в таблице "Отделы".
SELECT employee.ename, department.deptname
FROM employee
INNER JOIN department
ON employee.deptno = department.deptno
Упорядочение и структура реляционной схемы
Вот где важно использовать упорядочение реляционной схемы. Упорядочение - это процесс, который имеет цель хранения информации в самом подходящем месте. Никакая структура реляционных схем не является идеальной, но цель упорядочения - хранить конкретную информацию в одном месте для минимизации процессов обновления, удаления и ввода. Чем чаще информация дублируется в схеме, тем сложнее подтвердить ее достоверность.
На графике снизу изображена наша условная таблица "Сотрудники". В неупорядоченной модели, когда нам необходимо изменить расположение (колонка DEPTLOC) отдела 10 с “Pittsburgh” на “New York,” нам необходимо найти и обновить каждую строку, которая имеет DEPTNO=10. Приложение будет вынуждено изменить все строки с таблице сотрудников, которые содержат то значение DEPTNO (в нашем случае FOOT и ALLEN).
Вторая таблица - это наша вновь созданная таблица "Отделы". Если мы перенесем все связанные с отделами критерии в отдельную таблицу, то нам будет проще качественно обслуживать эти данные. Когда наше приложение потребует обновить информацию, связанную с отделом, то приложению не нужно будет обновлять многочисленные строки и, как часто бывает, еще и многочисленные таблицы (в зависимости от структуры схемы) для того, чтобы обеспечить последовательность всей информации, связанной с отделом.
Встроенные документы MongoDB, ссылки на справочную документацию и DBRefs
MongoDB, как и большинство продуктов NoSQL, не поддерживает операции соединения. Однако, MongoDB предоставляет некоторые альтернативы. Приведу для примера две наиболее распространенные из них:
Встроенные документы
Данные не упорядочены. В нашем примере информация об отделе сотрудника будет храниться в качестве встроенного документа в нашем документе "Сотрудники". Если необходимо поменять какую-либо информацию о наших отделах, необходимо будет соответственно просмотреть и обновить все документы сотрудников.
{ empno: 7388,
ename: ‘Foot’,
jobno: 87,
mgrno: 6599,
hiredate: new Date(‘Dec 12, 2015’),
department: {
deptno: 10,
deptname: ‘sales’,
depltloc: ‘Pittsburgh’
}
}
Ссылки на справочную документацию
Пользователи сохранят _ID field документа "Отделы" в документе "Сотрудники". Приложение выполнит второй запрос, используя _ID field отдела для получения необходимых данных из сборника документов. Для обеспечения достоверности полей _ID fields в документах "Сотрудники" приложение должно будет программным образом поддерживать их значения.
{ empno: 7388,
ename: ‘Foot’,
jobno: 87,
mgrno: 6599,
hiredate: new Date(‘Dec 12, 2015’),
department_id_locator: <object ID of Department 10 Document>
}
DBRefs
DBRefs - это ссылки с одного документа на другой с использованием _id field первого документа, имени сборника и, как опция, имени базы данных. Благодаря включению этих имен, DBRefs позволяет документам, хранящимся во множественных сборниках, более легко связываться с документами из какого-то одного сборника. Для обработки DBRefs наше приложение должно выполнить дополнительные запросы для получения выборки из ссылочных документов. Некоторые движки MongoDB имеют вспомогательные методы, которые автоматически формируют запросы для DBRef.
$LOOKUP (Ступень агрегирования)
MongoDB 3.2 имеет оператор $lookup, который теперь может быть включен в качестве ступени в процесс агрегации. $lookup совершает операцию "left outer join" по отношению к неразделяемым сборникам в одной и той же базе данных для фильтрации документов из "объединенного" сборника и последующей их обработки. Ступень $lookup ищет полное соответствие между полями в исходных документах и полями документов из "объединенного" сборника.
Обзор последующих статей
В следующей статье из этой серии мы обсудим процессы манипулирования данными и их удаления. Мы закончим серию о системах доступа к базам данных, сделав обзор сильных и слабых сторон как реляционных, так и NoSQL-систем. Затем мы продолжим нашу серию по сравнению реляционных и NoSQL-систем, обсудив поддержку транзакций и механизмы блокировки.
Спасибо за чтение!