Все базы данных NoSQL являются неструктурированными. Когда вы хотите хранить данные в реляционной базе, сначала определяете схему базы данных, т.е. указываете, какие существуют таблицы и столбцы, и задаете типы данных, которые могут содержаться в этих столбцах. Прежде чем сохранить данные, вы должны иметь схему для этого.
В базах данных NoSQL хранение данных происходит много проще. Хранилище типа “ключ—значение” позволяет хранить данные по ключу. Документная база данных по существу делает то же самое, поскольку она не накладывает ограничений на структуру хранящихся документов. Семейство столбцов позволяет хранить любые данные в любом столбце. Графовые базы данных позволяют свободно добавлять новые ребра, а также новые свойства в узлы и ребра.
Сторонники неструктурированных баз данных подчеркивают их свободу и гибкость. Имея схему, вы должны заранее угадать, что вам потребуется хранить, а сделать это бывает трудно. Используя неструктурированные базы данных, вы можете легко изменять хранилище данных, по мере увеличения знаний о своем проекте. Обнаруживая новые сущности, вы можете легко их добавлять. Более того, если выяснится, что некую сущность вам больше не надо хранить, вы можете просто перестать это делать, не беспокоясь о потере старых данных. Работая с реляционной схемой, вы должны были бы обеспечить сохранность старых данных при удалении столбцов.
Помимо обеспечения удобных изменений, неструктурированные базы данных облегчают обработку неоднородных данных, т.е. данных, в которых все записи имеют разные наборы полей. Схема помещает все строки таблицы в “смирительную рубашку”. Это может оказаться неудобным, если в разных строках хранятся разные данные. Вы либо останетесь с множеством столбцов, заполненных нулями (т.е. с разреженной матрицей), либо с бессмысленными столбцами вроде custom column 4
. Неструктурированные базы данных позволяют избежать этого, позволяя каждой записи хранить все, что требуется, — ни больше ни меньше.
Отсутствие структуры выглядит привлекательно. Это позволяет избежать многих проблем, существующих в базах данных с фиксированной схемой, но порождает новые. Если вы только храните данные и выводите их на экран в виде простого списка, состоящего из строк fieldName: value
, то неструктурированные базы данных — это то, что нужно. Но обычно мы делаем с базами не только это. Как правило, мы пишем программы для обработки данных, которые должны знать, что адрес заказчика, например, называется billingAddress
, а не addressForBilling
, а поле quantify
будет хранить целое число 5
, а не слово five
.
Крайне важный, хотя и неудобный факт заключается в том, что когда мы пишем программу, получающую доступ к данным, она практически всегда подразумевает какую-то форму неявной схемы. За исключением случаев, когда мы пишем простой код наподобие
//псевдокод
foreach (Record r in records)
foreach (Field f in r.fields)
print (f.name, f .value)
}
}
мы должны подразумевать определенные имена полей и некоторые осмысленные данные, а также делать предположения о типах данных, хранящихся в этих полях. Программа — не человек, она не может прочитать слово “qty
” и сделать вывод, что оно означает “quantity
”, — по крайней мере, если вы не запрограммировали ее на это. Итак, даже в неструктурированных базах данных обычно существует неявная схема — набор предположений о структуре данных в коде, манипулирующем этими данными.
Наличие неявной схемы в коде приложения порождает несколько проблем. Неявная схема означает, что, для того чтобы понять, какие данные хранятся в базе, вы должны заглянуть в код приложения. Если этот код хорошо структурирован, вы сразу найдете место, по которому можно определить схему. Но это ничем не гарантируется; все зависит от того, насколько ясным является код. Более того, база данных никак не отражает наличие схемы — она просто не может использовать схему, чтобы помочь вам выбрать способ хранения данных и эффективно извлекать их. Она не может предотвратить несогласованное манипулирование данными в разных приложениях.
Существует несколько причин, по которым реляционные базы данных имеют, а большинство баз данных в прошлом имели фиксированную схему. Схема имеет большое значение, а отрицание схем в базах данных NoSQL выглядит довольно пугающим.
По существу, неструктурированные базы данных переносят схему в код приложения, который к ней обращается. Это становится проблематичным, если к базе данных обращаются несколько приложений, разработанных разными людьми. Эти проблемы можно смягчить несколькими способами. Один из них — инкапсулировать все взаимодействия с базой данных в отдельном приложении и интегрировать его с другими приложениями через веб-сервисы.
Это соответствует современным предпочтениям многих людей, желающих обеспечить интеграцию с помощью веб-сервисов. Другой подход основан на четком разграничении разных областей агрегата, открытых для доступа разных приложений. Это могут быть разные разделы в документной базе данных или разные семейства столбцов в базе данных типа “семейство столбцов”.
Несмотря на то что сторонники технологии NoSQL часто критикуют реляционные схемы за негибкость, эта критика не совсем справедлива. Реляционные схемы можно изменить в любой момент с помощью стандартных SQL-команд. По мере необходимости можно создать новые столбцы специальным образом, чтобы хранить в них неоднородные данные. Нам редко приходилось это делать, но это вполне возможно. Тем не менее неоднородность данных — хороший аргумент в пользу неструктурированных баз.
Неструктурированность оказывает большое влияние на изменения, происходящие со временем в структуре баз данных, особенно хранящих однородные данные. Несмотря на то что управление изменениями схемы реляционных баз данных практикуется реже, чем требовалось, это вполне возможно. Аналогично необходимо управлять изменениями, происходящими в способах хранения неструктурированных баз данных, чтобы пользователь мог легко извлечь как старые, так и новые данные. Более того, гибкость неструктурированных баз данных проявляется только внутри агрегата. Если вам требуется изменить границы агрегата, то перенос каждого бита окажется таким же сложным, как и в реляционных базах. Вопросы миграции баз данных мы обсудим позднее.