Pull to refresh

Neo4j VS MySQL

Reading time 5 min
Views 27K

Предисловие


Будучи студентом третьего курса, я выбрал тему для курсовой роботы: «Графовые базы данных на примере Neo4j». Так как до того времени я изучал и использовал исключительно реляционные БД, мне было интересно, зачем вообще графовая БД и когда ее способности лучше применять? После просмотра множества сайтов в интернете я обнаружил только теорию и не больше. Так как теория не всегда убедительная и хотелось бы увидеть какую либо статистику, у меня разыгралось любопытство и я решил, что в своей курсовой я этим займусь, а в качестве противника Neo4j я выбрал MySQL.

Итак, кто же выиграет это противостояние?

Коротко о Neo4j и графовых БД


Neo4j — open-source графовая база данных, история которой началась по инвестициям компании «Neo Technology» в 2003 году. С 2007 года стала публично доступной. В Neo4j присутствуют все характеристики баз данных, включая соблюдение ACID, поддержание разбиение на кластеры и восстановления после сбоя в системе. Сегодня является лидером среди графов баз данных.

ACID (Atomicity, Consistency, Isolation, Durability) — набор свойств, которые гарантируют надежную работу транзакций.

Компоненты графовой базы данных — узлы и ребра. Они могут быть дополнены собственным набором полей. Модель такой БД схематично изображена на рисунке.



Сохранение данных в Neo4j


Файл nodestore.db содержит определенный размер записей, содержащих информацию о Ноды:
1. Метка, которая показывает, запись активна;
2. Указатель на первое отношение, которое содержит данная нода;
3. Указатель на первую свойство, которое содержит данная нода.

Нода не содержит собственного идентификатора. Так как каждая запись в nodestore.db занимает одинаковое количество места, можно рассчитать указатель на ноду.

Файл relationshipstore.db также содержит записи одинакового размера, которые описывают отношения, но они состоят из следующих элементов:

1. Метка, которая показывает, запись активна;
2. Указатель на ноду, которая содержит это отношение;
3. Указатель на ноду, к которой это отношение направлено;
4. Вид отношения;
5. Указатель на отношение, которое стоит впереди (в пределах данной ноды);
6. Указатель на отношение, которое стоит сзади (в пределах данной ноды);
7. Указатель на отношение, которое стоит впереди (в пределах Ноды, в которой это отношение направлено);
8. Указатель на отношение, которое стоит сзади (в пределах Ноды, в которой это отношение направлено);
9. Указатель на первое свойство данного отношения.

Наполнение данными


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

Мною была выбрана предметная область — социальная сеть. Я построил ER диаграмму, на основе которой создал реляционную и графовую модели.



После этого я заполнил MySQL данными, создав класс генерации этих данных и методы, которые вносили новые данные в БД.
Количество данных, которые были внесены в MySQL:

addUsers(100 000); — количество пользователей.
addGroups(200 000); — количество групп.
addPhotos(300 000); — количество фотографий.
addAudio(250 000); — количество аудиозаписей.
addFriendships(1 000 000); — количество друзей.
addMessages(4 000 000); — количество сообщений.
addUserAudio(350 000); — количество аудиозаписей.
addUserGroups(400 000); — количество групп пользователей.
addUserPhoto(400 000); — количество фотографий пользователей.

Потом я конвертировал эти данные в Neo4j. Стоит заметить, что заполнение БД у меня отняло очень много времени. Если вы решите провести что-то подобное самостоятельно, готовьтесь к тому, что либо потратите много времени, либо не используйте полей с текстом (думаю, это заняло много времени в моем случае). После этого я сравнил место, которое занимает информация в Neo4j и MySQL. Был небольшой шок, для реляционной БД надо было 351.5 МБ, а для графовой – 3.45 ГБ. Теперь приступим к экспериментам.

Эксперимент 1


Описание эксперимента: измерение времени поиска пользователя по его идентификатору.

В этом эксперименте я искал пользователей за их идентификатором определенное количество раз. Для этого я написал методы, код которых представлено ниже.

public static void main(String[] args){
    // Database connection initialisation
    init();

    int [] counts = {10, 100, 1000, 5000, 10000, 30000, 60000, 90000, 120000};
    for(int i = 0; i < counts.length; i++){
        findUserByIDTest(counts[i]);
    }
}

static void findUserByIDTest(int count){
    System.out.println("__________________________________");
    System.out.println("STATISTIC FOR COUNT: " + count);

    {
        Random r = new Random(count);
        long time = - System.currentTimeMillis();

        for (int i = 0; i < count; i++) {
            int id = r.nextInt(100000);
            User u = MySQLDAO.getUserByID(id);
        }

        time += System.currentTimeMillis();
        System.out.println("Time for MySQL:" + time);
    }
    {
        Random r = new Random(count);
        long time = - System.currentTimeMillis();

        for (int i = 0; i < count; i++) {
            int id = r.nextInt(100000);
            User u = Neo4jDAO.getUserByID(id);;
        }

        time += System.currentTimeMillis();
        System.out.println("Time for Neo4j:" + time);
    }
    System.out.println("__________________________________");
}

После выполнения программного кода я составил таблицу и нарисовал построил диаграмму к ней. Результаты меня порадовали. Neo4j замечательно справилась.
User count = 100000

Number of queries

Time for MySQL, ms

Time for Neo4j, ms

10

4

9

100

34

76

1000

286

510

5000

1034

1103

10000

1340

1187

30000

3390

1384

60000

6876

2102

90000

10537

3175

120000

14033

3858




Эксперимент 2


Описание эксперимента: измерение времени нахождения друзей пользователя с изменением величины интервала вхождения идентификаторов для поиска.

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



При любом раскладе, время графовой базы для поиска на больших данных было меньше, чем то, которое надо реляционной.

Эксперимент 3


Описание эксперимента: измерение времени нахождения общего количества фотографий у пользователей, которые администрируют хотя бы одну группу, в зависимости от диапазона значений идентификаторов пользователя.

Этот эксперимент очень похож на предыдущий, но является более сложным. Если значения времени в предыдущих экспериментах при повторениях отличались слабо, то в этом скачки куда сильнее. Поэтому я провел этот эксперимент три раза и составил соответствующую таблицу.
User count = 100000, Photo count = 300000, User photo count = 400000

experiment 1

experiment 2

experiment 3

id range <

Time for MySQL, ms

Time for Neo4j ,ms

Time for MySQL, ms

Time for Neo4j, ms

Time for MySQL, ms

Time for Neo4j, ms

10

299

11339

164

92594

456

56575

100

10652

2748

674

2400

663

2826

1000

7243

4931

5433

2481

5649

1942

5000

22538

5521

23747

2408

23522

3514

10000

47755

5627

44917

2650

44992

1844

30000

137572

8161

33856

3108

136592

3707

60000

64002

13577

300814

5004

280672

6029

90000

482329

13475

438875

5102

429304

5631







После обсуждений на хабре, я попробовал изменил подход к условиям эксперимента: поправил запрос, на более простой, перед каждым экспериментом подымал заново MySQL и додерживался условия, что не должны работать MySQL и Neo4j одновременно. Вышло следующее: график MySQL стал более стабильным, а графовая бд начала очень сильно проигрывать реляционной на небольших объёмах данных.

experiment 1
id range <
Time for MySQL, ms
Time for Neo4j,ms
10
120
10767
100
690
10706
1000
5879
10884
5000
24668
12245
10000
52462
12280
30000
154534
13352
60000
296369
14545
90000
489830
18058



Скромные выводы


Смело могу сказать, что графовая база данных нуждается в намного меньшем временем в поиске на больших объемах данных, однако места на жёстком диске она занимает куда больше. Поэтому для небольших систем лучше использовать реляционную БД или искать альтернативу среди других NoSQL баз данных.

Спасибо за внимание.
Tags:
Hubs:
+5
Comments 35
Comments Comments 35

Articles