Ответ, к сожалению, таков: ваше соображение совершенно правильно во всех отношениях. Вы должны хранить узлы (вершины) в одной таблице, а Edges ссылаются на FromNode и ToNode для преобразования структуры данных графа в реляционную структуру данных. И вы также правы, что это приводит к большому количеству поисков, потому что вы не можете разбить его на подграфы, которые могут быть запрошены сразу. Вы должны пройти от узла к краю к узлу, от края к узлу ... и т. Д. (Рекурсивно, пока SQL работает с наборами).
Дело в том, что ...
Реляционный, Графо-ориентированный, Объектно-ориентированный, Документный - это различные типы структур данных, которые отвечают различным требованиям. Вот о чем идет речь и почему возникло так много разных баз данных NoSQL (большинство из них - простые хранилища документов), потому что просто не имеет смысла организовывать большие данные реляционным способом.
Альтернатива 1 - Графо-ориентированная база данных
Но существуют также графо-ориентированные базы данных NoSQL, которые делают графическую модель данных первоклассным гражданином, таким как OrientDB с которым я сейчас немного играюсь. Приятно то, что, несмотря на то, что они сохраняют данные в виде графика, они все равно могут быть использованы как в реляционном, так и даже объектно-ориентированном или документно-ориентированном способах (т. Е. Путем запросов с простым старым SQL). Тем не менее обход графика является оптимальным способом получить из него данные наверняка.
Альтернатива 2 - работа с графами в памяти
Когда дело доходит до быстрой маршрутизации, фреймворки маршрутизации, такие как Graphhopper , создают полный граф (миллиарды узлов) внутри памяти Поскольку Graphhopper использует MemoryMapped-реализацию своего GraphStore, это работает даже на устройствах Android, требующих только несколько МБ памяти. Полный график считывается из базы данных в память при запуске, и затем выполняется маршрутизация, поэтому вам не нужно искать базу данных.
Похоже, вы бы сделали что-то вроде этого:
boost::shared_mutex _access;
void reader()
{
// get shared access
boost::shared_lock<boost::shared_mutex> lock(_access);
// now we have shared access
}
void writer()
{
// get upgradable access
boost::upgrade_lock<boost::shared_mutex> lock(_access);
// get exclusive access
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
// now we have exclusive access
}