2017-01-11 4 views
0

Я выполняю некоторые тесты производительности memsql на выборочных данных и имею очень плохое поведение при запросе данных JSON. У меня есть 2 таблицы, которые выглядят очень похожими и содержат точно такую ​​же информацию (загружается из одного и того же файла csv). Разница в том, что столбец segments является JSON vs varchar (255).Производительность поиска в MemSQL: JSON vs varchar

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 раз медленнее, чем% х% LIKE. Есть ли что-то, что может улучшить его?

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

На всякий случай некоторые технические характеристики. 3 идентичных сервера с голой металликой. 1 для агрегатора, 2 для данных. У каждой машины есть NUMA, поэтому всего 4 листа. Быстрые SSD, 32Cores (2 X [email protected]), 32 ГБ оперативной памяти.

ответ

1

Я не удивлен, что это медленно. MemSQL использует сжатие на основе паркета для столбца json, и у нас нет таких видов быстрых поисков еще (но следите за обновлениями!).

Есть несколько вариантов. Один, если вы всегда будете искать 42, вы можете использовать постоянный столбец (https://docs.memsql.com/docs/persistent-computed-columns). Это вряд ли будет вашим прецедентом.

Другой вариант: если вы всегда смотрите на тот же массив, вы можете создать нормализованную таблицу (https://en.wikipedia.org/wiki/Database_normalization).
SOmething like create table test_events_array (timestamp datetime not null, user_id bigint not null, segment bigint, shard(user_id), key(ts) using clustered columnstore) затем select count(*) from test_events_array where segment=42 будет молниеносно.

Он также сжимает до почти ничего с этой схемой.

Смежные вопросы