Одна из моих личных целей — каждый год изучать новую технологию. До сих пор я в основном имел дело с реляционными базами данных SQL, поэтому целью этого года было научиться работать с различными типами баз данных, такими как базы данных NoSQL. Я хотел узнать больше о блестящих новых технологиях, которые я мог спутать с покемонами, такими как Redis или Hadoop. Это то, что представляет собой это руководство; абсолютное базовое введение в NoSQL, где я перечисляю четыре наиболее распространенных типа альтернатив SQL, предоставляю краткое введение в каждый из них, описываю их основные отличия от реляционных баз данных и объясняю, когда следует выбирать этот тип базы данных. Это не руководство по технической реализации, и я не буду обсуждать конкретные технологии NoSQL, такие как Redis или MongoDB, за исключением использования их в качестве примеров.

Естественно, первый вопрос, который я задал, был что такое NoSQL?. Ответ на этот вопрос довольно плохой; никто не может сказать вам, что такое NoSQL. Во-первых, это не противоположность реляционной базе данных. Все базы данных NoSQL поддерживают отношения, а иногда даже лучше, чем реляционные базы данных, такие как графовые базы данных (поэтому термин реляционный на самом деле является неправильным). Это не буквально No SQL; существуют базы данных NoSQL, которые имеют SQL-подобный синтаксис (Apache Hive). Дело не в том, что она не соответствует ACID, потому что нет ничего, что мешало бы базе данных NoSQL быть ACID-совместимой (хотя большинство из них являются BASE: Bв основном Aдоступными, Sмягкое состояние, Eконсистенция между событиями). Дело не в отсутствии схем, не в отсутствии транзакций, не в распределенности или горизонтальном масштабировании и уж точно не в открытом исходном коде. Все, что я знаю, это то, что NoSQL, безусловно, неMySQL.

Хорошо, не ясный ответ, но, по крайней мере, у меня есть смутное понимание всего, чем NoSQL не является. Чтобы лучше понять NoSQL, давайте перейдем к другому вопросу: Что делают базы данных NoSQL? Я сравню несколько различных типов баз данных с реляционными базами данных SQL; Давайте сравним хранилища столбцов, базы данных документов, хранилища ключей и значений, базы данных графов и базы данных объектов. Я буду использовать одну и ту же структуру для каждого раздела, отвечая на три вопроса; Что это такое?,Когда мне следует его использовать? и, наконец, Почему бы мне просто не использовать для этого реляционную базу данных? откровенно говоря, реляционные базы данных так долго были стандартом де-факто, что они могут делать большинство вещей, которые могут делать базы данных NoSQL (но то, что вы можете, не означает, что вы должны!).

Магазины колонок

Начнем с типа базы данных, близкого к реляционным базам данных на основе строк. Как вы, наверное, знаете, реляционная база данных хранит данные в таблицах, упорядоченных по сетке столбцов и строк. Чтобы получить конкретное значение, вам нужно знать уникальный идентификатор (или какой-либо другой уникальный идентификатор) и столбец. Таблица может выглядеть примерно так:

ID    Lastname     Firstname   Age     Salary
1     Oostveen     Rik         25      40000
2     Brandenburg  Frederik    30      50000
3     Plomp        Rik         27      44000
4     Brandenburg  Bart-Jan    35      55000
5     Schaper      Peter       18      25000

База данных столбца, с другой стороны, хранит базу данных по столбцу. Это кажется странным, поскольку вы также можете упорядочить таблицу по столбцам, но остановитесь на мне: точно такие же данные в базе данных столбцов будут выглядеть примерно так:

Lastname      Oostveen(1);Brandenburg(2,4);Plomp(3);Schaper(5)
Firstname     Rik(1,3);Frederik(2);Bart-Jan(4);Peter(5)
Age           25(1);30(2);27(3);35(4);18(5)
Salary        40000(1);50000(2);44000(3);55000(4);25000(5)

Здесь вы можете увидеть немедленное преимущество; неуникальная фамилия «Бранденбург» и неуникальное имя «Рик» не хранятся дважды, они сгруппированы вместе! Но есть и другой пример.

В реляционной таблице, если вы хотите получить мою информацию, вы должны сделать оператор вроде SELECT * FROM Employees WHERE Firstname = «Rik» AND Lastname = «Oostveen». Если вы найдете совпадающие строки, вы немедленно получите всю информацию; довольно аккуратно. Однако эти данные не упорядочены; если бы столбец с фамилией был упорядочен по алфавиту, вы могли бы просто искать букву О так же, как вы искали бы букву О в словаре, вместо того, чтобы проверять каждую строку. Это не так, поэтому теперь вам нужно проверить каждое значение, чтобы убедиться, что оно совпадает. В реляционной базе данных вы можете решить эту проблему, создав индекс:

ID    Lastname     
2     Brandenburg  
4     Brandenburg
1     Oostveen
3     Plomp
5     Schaper

Теперь вы сразу знаете, что вам нужно только проверить идентификатор 1, чтобы увидеть, соответствует ли имя «Рик»! Аккуратный! Но что, если в следующий раз вы захотите выбрать кого-то по возрасту? Для этого вам также придется создать индекс.

В базе данных столбцов вы можете просто отсортировать саму таблицу и рассматривать всю таблицу как большой индекс:

Lastname      Brandenburg(2,4);Oostveen(1);Plomp(3);Schaper(5)
Firstname     Bart-Jan(4);Frederik(2);Peter(5);Rik(1,3)
Age           18(5);25(1);27(3);30(2);35(4)
Salary        25000(5);40000(1);44000(3)50000(2);55000(4)

Если вы хотите получить зарплату того, кому 18 лет, столбец (далее я буду называть его строкой, так как я отобразил его в виде строки в этой таблице! не запутайтесь!) уже говорит вам, что это человек с идентификатором 5. Вы можете игнорировать имя и фамилию, теперь вам нужно только найти строку зарплаты для идентификатора 5. Вы хотите подсчитать всех с фамилией Бранденбург? Посмотрите, увидите, что есть два идентификатора, и вы получили свой счет, даже не глядя на какую-либо другую информацию. Вы хотите знать, сколько людей имеют зарплату от 40000 до 50000? Посмотрите на строку зарплаты, посчитайте ее, увидите, что там 3, игнорируйте все остальное.

Стало намного проще искать отдельные сведения, но компромисс заключается в том, что вы не можете сразу получить всеинформацию о ком-то. Если я хочу знать все о «Рике Ооствине», мне все равно придется сначала просмотреть столбец с фамилией, увидеть, что идентификатор кого-то с фамилией «Оствеен» равен 1, а затем проверить строку с первым именем, чтобы увидеть, есть ли кто-то. по имени «Рик» с идентификатором 1. Хуже того, если я хочу получить свой возраст и зарплату, мне нужно просмотреть эти строки, чтобы увидеть, есть ли кто-то с идентификатором 1. Таким образом, этот тип базы данных лучше всего использовать для сложных запросов к столбцу. уровне вместо того, чтобы каждый раз получать полную модель данных.

Небольшое примечание здесь; обычно вы хотите упорядочить столбец в базе данных столбцов по малой мощности, а не по алфавиту как таковому.

Базы данных документов

Я собираюсь продолжить предыдущий пример. Я также хочу хранить адресную информацию о сотрудниках. Valtech довольно большая компания, и я хочу быть готовым к уникальным ситуациям, с которыми я могу столкнуться в крупной компании; у некоторых сотрудников может быть несколько адресов, а у некоторых сотрудников может быть один и тот же адрес. Муж и жена, может быть, просто соседи по комнате, так бывает. У каждого сотрудника может быть несколько адресов, у каждого адреса несколько сотрудников.

Это будет связь «многие ко многим» в реляционной базе данных. Но теперь мне нужно присоединение каждый раз, когда мне нужно что-то такое простое, как домашний адрес сотрудника, что-то, что по своей сути является частью личной информации сотрудника. Кроме того, адреса, вероятно, уникальны для 99% сотрудников. Может случиться так, что два сотрудника имеют один и тот же адрес, но, скорее всего, это не так.

Есть еще одна проблема; моя схема не соответствует. Valtech — международная компания, и не во всех странах адресная информация используется одинаково. Теперь мне нужно создать столбцы для поддержки всех типов адресов, с которыми я могу столкнуться. Я также мог бы немного нормализовать свои данные, поместив их в одну адресную строку, что является лучшим техническим решением, но теперь я больше не могу фильтровать данные, например, выбирать всех сотрудников в определенном голландском почтовом индексе, предполагая, что они Имеется.

Самое простое решение — вообще не заботиться о строго типизированной адресной информации. Вместо моей строгой реляционной модели в базе данных документов хранится буквально только документ. Самый простой пример — документ JSON, который также используется во многих базах данных документов. Меня больше не волнует строгая схема, какая необязательная информация заполняется или нет, или как может выглядеть адрес в Японии.

{  
   "Employees":[  
      {  
         "ID":1,
         "Firstname":"Rik",
         "Lastname":"Oostveen",
         "Age":25,
         "Position":1,
         "Salary":40000,
         "Addresses":[  
            {  
               "Street":"Pleintjesweg",
               "Housenumber":200,
               "Addition":"achter",
               "Zipcode":"111AA",
               "City":"Amsterdam",
               "Country":"the Netherlands"
            }
         ]
      },
      {  
         "ID":2,
         "Firstname":"Frederik",
         "Lastname":"Brandenburg",
         "Age":30,
         "Position":2,
         "Salary":50000,
         "Addresses":[  
            {  
               "Zipcode":"〒100-8994",
               "Prefecture":"Tokyo-to",
               "Ward":"Chuo-ku",
               "District":"Yaesu 1-chome",
               "Lot":"block 5 lot 3",
               "Country":"Japan"
            }
         ]
      },
      {  
         "ID":3,
         "Firstname":"Rik",
         "Lastname":"Plomp",
         "Age":27,
         "Salary":44000,
         "Addresses":[  
            {  
               "Street":"Boulevard Frère Orban, 27",
               "Zipcode":"4000",
               "City":"Liège",
               "Country":"Belgium"
            },
            {  
               "Street":"164 Boulevard de Verdun",
               "Zipcode":"94120",
               "City":"Fontenay-sous-Bois",
               "Departemant":"Seine-Saint-Denis",
               "Country":"France"
            }
         ]
      }
   ],
   "Positions":[  
      {  
         "ID":1,
         "Name":"Developer",
         "Starting_Salary":20000
      },
      {  
         "ID":2,
         "Name":"Designer"
      }
   ]
}

Довольно простая структура данных, и я могу сохранить ее как есть в своей базе данных документов. Теперь я поддерживаю несколько адресов, но это по-прежнему неотъемлемая информация моих данных — она не в отдельной таблице, это часть самих данных. Если я хочу узнать адресную информацию сотрудника, мне не нужно выполнять соединение, мне просто нужно запросить этого сотрудника. В то же время я все еще могу использовать повторно используемый идентификатор для данных, которые я действительно хочу повторно использовать, в данном случае для позиций. Таким образом, база данных документов лучше всего подходит для данных без схемы, предпочтительно с небольшим количеством отношений. Основным преимуществом базы данных документов является ее гибкость.

Хранилища ключей-значений

Хорошо, следующий очень простой: хранилище "ключ-значение". Если вы похожи на меня, вы, вероятно, думаете о простом примере, когда слышите пары «ключ-значение»: словарь или набор хэшей! И ты не за горами! Хранилище ключ-значение очень простое; есть уникальный ключ, и он связан со значением. Хорошим примером является вариант словаря из реальной жизни; есть ключ (слово) со значением (определением). Теперь, просто для придирки, вы могли бы сказать, что в реальном словаре ключи не уникальны (слово может означать разные вещи, например, что свинец — это либо тип металла, либо акт направления чего-то или кого-то), но большинство словарей имеют уникальные ключи; они не определяют одно и то же слово несколько раз, а просто перечисляют разные определения под одним и тем же словом.

Причина, по которой я упоминаю об этом, заключается в том, что это несколько важно для объяснения разницы между реляционной базой данных, которая опрашивается только по первичному ключу, и хранилищем «ключ-значение»; Чтобы реализовать список значений, связанных с первичным ключом в реляционной базе данных, вы, вероятно, уже просматриваете разные таблицы и реализуете первичный ключ как внешний ключ в другой таблице, которая имеет свой собственный первичный ключ. Хранилище ключей-значений не заботится об этом; что касается хранилища "ключ-значение", список значений являетсязначением.

На самом деле, большинству хранилищ ключей-значений совершенно все равно, какое значение хранится; некоторые даже позволяют хранить различные типы значений. Возможно, ключ «timeout_duration» — это число, а «redirect_after_login» — это URI. Хранилищу ключ-значение все равно, если ключи одного типа. Большинство хранилищ ключей и значений, таких как Redis, не требуют предварительного определения типа данных значения, как это делают реляционные базы данных, и даже допускают различные типы значений для каждого ключа.

На самом деле значение вообще не важно в хранилище значений ключа; Хотя поиск по разным столбцам в реляционной базе данных является логичным шагом, его нет в хранилище ключей и значений. У вас есть ключ, и вам нужно значение, и вы никогда не должны искать различные свойства значения в хранилище пар «ключ-значение», а большинство хранилищ «ключ-значение» даже этого не позволяют. В свою очередь, в самом ключе должно быть как можно меньше данных.

Итак, что может быть примером? Кэширование и настройка файлов могли быть. Вы хотите хранить в кеше разные значения, если они имеют уникальный ключ кеша. Вы могли бы, например, сделать что-то вроде этого:

"SearchOptions" : ["Suggest", "Facet", "Filter", "Highlight", "Sort", "Page"]
"SuggestionsShown" : 30
"EnabledFacets" : [3, 5, 8, 11]
"Filter" : Filter.DirtyWordsOnly
"HighlightingEnabled" : true
"DefaultSorting" : Keyword.Alphabetical.Ascending
"DefaultPage" : 1

Теперь, конечно, вы также можете создать документ из этого и сохранить его в хранилище документов. Так в чем разница? Ну, во-первых, вам не нужно получать весь документ каждый раз, когда вам нужна одна настройка. Но по сути, ключ-значение — это гораздо более простая форма хранилища документов. Хранилище документов часто имеет больше функций, таких как индексация значений, но если вам нужен только поиск по ключу-значению, вам подойдет хранилище с ключом-значением.

Так что это тоже главное преимущество перед реляционной базой данных; реляционная база данных требует обслуживания базы данных, хорошей и жесткой схемы, вы должны подумать об этом. Не хранилище ключей-значений. У меня есть ключ, я храню значение, вот и все. Никаких внешних ключей, никакой схемы, никаких индексов (ключ таблицы — единственный «индекс», который вам нужен), просто очень простое хранилище данных.

Базы данных графов

Далее идет графовая база данных. Несмотря на название, реляционные базы данных на самом деле не так хороши в представлении отношений; вы не можете сделать намного больше, чем отношение «один к одному» или отношение «один ко многим», а второе уже требует соединительной таблицы. Отношения очень структурированы и жестки в организации; если у вас есть внешний ключ для одной таблицы, вы не можете присвоить значение из другой таблицы или не во внешней таблице. Соединения рассчитываются во время запроса, сопоставляя внешний ключ одной таблицы с первичным ключом другой; это довольно интенсивно, и обычно рекомендуется не слишком углубляться в соединения, так как это обычно убивает производительность. Серьезно, не делайте многоуровневых соединений.

Однако база данных графов сосредоточена на отношениях. Вы по-прежнему можете хранить данные, как в реляционной базе данных, но они хранятся немного по-другому. Во-первых, каждая запись данных, которую вы хотите сохранить (которая может быть строкой в ​​реляционной базе данных), является узлом или вершиной (множественное число вершин) в базе данных графа. У них все еще есть свойства, которые вы храните в ячейках; например, таблица «Человек» может иметь запись с уникальным идентификатором «1228472» со свойством (столбец) «Имя», где имя будет установлено в ячейке, у вас может быть узел с именем «1228472» с тем же свойством « Имя". Чего не хватает, так это стола; это не отображается один к одному, потому что вы назначаете метку узлу; узел «1228472» будет иметь метку «Человек», но, возможно, вы могли бы назначить ему и несколько других меток!

Далее идут отношения, называемые ребрами в базе данных графа. В отличие от реляционных баз данных, эти отношения имеют Тип, Направление (могут быть двунаправленными) и собственный набор свойств. Таким образом, у вас может быть узел «1228472» с меткой «Person», который имеет двунаправленную связь «works_at» с узлом «Valtech» с меткой «Company», где связь имеет свои собственные свойства, такие как «Start_Date» или "Название работы". Это возможно в соединительной таблице, но не в однонаправленном отношении в реляционных базах данных SQL.

Вы получаете что-то вроде паутины, где разные отношения идут от одного узла к другому. Это будет выглядеть примерно так:

На данный момент это все еще не слишком сложно сделать с реляционной базой данных, но вы можете видеть, что она сразу становится немного сложнее, и вам нужно знать немного больше об отношениях:

Хотя эта диаграмма по-прежнему имеет смысл, если вы знакомы с реляционными диаграммами, она стала намного менее интуитивной. Кроме того, получение информации типа «все, кто любит металл и имеет собаку» приведет к сложным соединениям, особенно с учетом того, что в нашей текущей таблице, где люди могут любить несколько типов музыки и иметь несколько домашних животных, что приводит к многим - много таблиц и быстро делает простую ситуацию сложной для моделирования. Это скользит по тому, что происходит, если два объекта могут иметь несколько типов отношений; вы можете увидеть это с таблицей «братья и сестры» и «браки»; для каждого типа отношений, которые люди могут иметь с другими людьми, требуется новая таблица «многие ко многим»!

В базе данных графа вы просто объявляете имя отношения (узел «Лиза» isMarriedTo «Bob» и «Lisa» isSiblingOf «Mike») и все! Понятно, что графовая база данных намного лучше как для представления различных типов отношений, так и для их обхода. Если вы не хотите присоединяться дальше первого уровня, а ваши отношения остаются относительно простыми, реляционная база данных, вероятно, удовлетворит все ваши потребности.

База данных объектов

И последний по порядку но не по значимости; базы данных объектов. Объектные базы данных более тесно связаны с объектно-ориентированным программированием и часто привязаны к одному объектно-ориентированному языку. Они хранят данные и отношения близко к тому, как объект выглядит в коде, без предварительного сопоставления с полями и таблицами. Основное преимущество заключается в том, что вам не нужен объектно-реляционный сопоставитель, такой как Entity Framework (я в основном парень с .NET), что означает, что он запрограммирован с меньшими процедурными различиями внутри программы, чем могла бы быть реляционная база данных, особенно в случае сложных систем.

База данных объектов также поддерживает объектно-ориентированные функции, такие как объекты, модели, классы, наследование и пользовательские типы данных и методы (хотя часто хранятся в виде ссылок). Это делает базу данных очень простой в использовании, если она очень тесно связана с вашей реализацией. По сути, это постоянное хранилище объектов для вашего приложения — в результате основное внимание уделяется интеграции базы данных и системы, а не оптимизации данных.

Основным преимуществом объектной базы данных является также и ее ловушка; тесная взаимосвязь со структурой программирования делает ее простой в использовании в обмен на низкую гибкость, тесную связь с вашей реализацией и сложность оптимизации данных.

Надеюсь, вам понравился этот небольшой отрывок о четырех различных альтернативах баз данных SQL, и вы получили базовое представление о технологиях баз данных NoSQL. Правда в том, что реляционные базы данных все еще могут удовлетворить ваши потребности во многих случаях, но погружение в базы данных NoSQL и понимание того, когда (не) их использовать, научило меня многому в отношении структур данных и оптимизации. Я надеюсь, что это произошло и с вами.

Развлекайся!