Я запускаю некоторые тесты производительности memsql для выборочных данных и очень плохо себя чувствую при запросе данных JSON. У меня есть две таблицы, выглядящие очень похожими и содержащие одинаковую информацию (загруженную из одного и того же CSV-файла). Разница в том, что столбец segments
— это JSON, а не varchar(255).
CREATE TABLE `test_events` (
`timestamp` datetime NOT NULL,
`user_id` int(20) NOT NULL,
`segments` JSON COLLATE utf8_bin NOT NULL,
KEY `timestamp` (`timestamp`) /*!90619 USING CLUSTERED COLUMNSTORE */,
/*!90618 SHARD */ KEY `user_id` (`user_id`)
CREATE TABLE `test_events_string` (
`timestamp` datetime NOT NULL,
`user_id` int(20) NOT NULL,
`segments` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
KEY `timestamp` (`timestamp`) /*!90619 USING CLUSTERED COLUMNSTORE */,
/*!90618 SHARD */ KEY `user_id` (`user_id`)
И пример данных (количество элементов в массиве варьируется от 1 до 20):
memsql> select * from test_events limit 1;
+---------------------+---------+------------------------+
| timestamp | user_id | segments |
+---------------------+---------+------------------------+
| 2017-01-04 00:00:00 | 26834 | [19,18,9,6,7,22,34,43] |
+---------------------+---------+------------------------+
Ниже приведены 2 запроса, которые извлекают одну и ту же информацию, но отличаются скоростью. Оба запроса были выполнены дважды, и я копирую 2-й запуск:
memsql> select count(*) from test_events where json_array_contains_double(segments, 42);
+----------+
| count(*) |
+----------+
| 79312103 |
+----------+
1 row in set (15.86 sec)
memsql> select count(*) from test_events_string where segments like '%42%';
+----------+
| count(*) |
+----------+
| 79312103 |
+----------+
1 row in set (1.96 sec)
memsql> select count(*) from test_events;
+-----------+
| count(*) |
+-----------+
| 306939340 |
+-----------+
1 row in set (0.02 sec)
Таким образом, сканирование JSON в 8 раз медленнее, чем %x% LIKE. Есть ли что-то, что может улучшить его?
Может быть, вы можете посоветовать, как решить эту проблему бизнес-логики с другим подходом? По сути, мы регистрируем события для пользователей и к каждому событию мы хотим прикрепить массив идентификаторов некоторых сущностей. Этот массив часто изменяется в течение жизненного цикла пользователя. Мы хотим выполнять фильтрацию запросов по 1 или нескольким идентификаторам, как в примере выше.
На всякий случай немного технических характеристик. 3 одинаковых bare metal сервера. 1 сервер для агрегатора, 2 для данных. Каждая машина имеет NUMA, поэтому всего 4 листовых узла. Быстрые твердотельные накопители, 32 ядра (2 x E5-2650v2 @ 2,60 ГГц), 32 ГБ ОЗУ.