Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Большая таблица (масштабируемость?) / 25 сообщений из 38, страница 1 из 2
24.12.2015, 10:37:57
    #39136813
Barvinok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Добрый день!
Есть один проект, в рамках которого ведётся лог игровых событий для последующего анализа. Лог живёт в таблице, вот она в сокращённом виде:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE TABLE `eventlog` (
	`guid` CHAR(34) NOT NULL COMMENT 'Event GUID',
	`timestamp_raw` BIGINT(20) UNSIGNED NOT NULL COMMENT 'UNIX epoch in milliseconds',
	`timestamp_d` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Timestamp (human-readable)',
	`player_name` VARCHAR(20) NOT NULL COMMENT 'Event origin name',
	`player_guid` CHAR(34) NOT NULL COMMENT 'Event origin GUID',
	`loc1_name` VARCHAR(128) NULL DEFAULT NULL COMMENT 'Loc1 name',
	`loc1_guid` CHAR(35) NULL DEFAULT NULL COMMENT 'Loc1 GUID',
	`event_action` ENUM('CAPTURE','LINK','FIELD','NOLINK','NOFIELD','FRACKER','BEACON') NULL DEFAULT NULL COMMENT 'Event action',
	`plaintext` TEXT NOT NULL COMMENT 'Event plaintext'
)
COMMENT='Global event log'
COLLATE='utf8_general_ci'
ENGINE=MyISAM
;


Да, здесь нет индексов, в этом и проблема :(
Когда-то недавно, они были - для минимального анализа вот такие
Код: sql
1.
2.
3.
4.
5.
PRIMARY KEY (`guid`)
INDEX `timestamp_raw_idx` (`timestamp_raw`)
INDEX `player_name_idx` (`player_name`)
INDEX `player_guid_idx` (`player_guid`)
INDEX `loc1_guid_idx` (`loc1_guid`)


Но было это до тех пор, пока количество строк не превышало миллиона-двух и всё довольно шустро бегало.
Потом нам захотелось загрузить туда всю эпоху глобально и продолжать её отслеживать. Это за 3 прошедших месяца 400 миллионов строк, общим объёмом 145 GiB и плюс к тому ещё около 3-4 миллионов строк ежедневно должно добавляться.
Месяцы мы собирали отдельными SQL-файлами с инсертами, потом ужаснувшись скорости их загрузки в базу, загрузили их в клонированные таблицы без ключей, сделали SELECT INTO, потом из основной таблицы сделали LOAD INFILE, при этом в основной таблице пришлось тоже убрать индексы, иначе эта процедура затянулась бы на месяц или больше :(.
Теперь да, в единой таблице без индексов 400 миллионов строк и с этим что-то надо делать, т.к. никакие анализаторы не работают без индексов.
При попытке их добавить
Код: sql
1.
ALTER IGNORE TABLE `eventlog` ADD PRIMARY KEY (`guid`), ADD INDEX `timestamp_raw_idx` (`timestamp_raw`), ADD INDEX `player_name_idx` (`player_name`), ADD INDEX `player_guid_idx` (`player_guid`), ADD INDEX `loc1_guid_idx` (`loc1_guid`)


я вижу, что сервер начинает довольно бодренько писать временные MYD и MYI, кое-как доползает до отметки в 13 гигабайт MYD и полтора-два MYI и после этого скорость резко падает до черепашьей.
Я, в принципе, представляю, почему так происходит.
Наверное, PRIMARY KEY по CHAR(34) это плохая идея, но он там единственный гарантированно уникальный идентификатор каждого события.
Возможно, дело в том что сервер слабый - там всего 2 гигабайта оперативы и Pentium(R) Dual-Core CPU E5200 @ 2.50GHz.

Мы бы даже могли раскошелиться на более мощный сервер, если бы были точно уверены, что проблема именно в этом (что индексы не влазят в key buffer). Но тогда вопрос - а сколько ему надо? Если там линейная зависимость, то для базы в 400 млн строк ему понадобится, что ли, 55 гигабайт на индексы?
И нельзя забывать что ежедневно таблица будет расти на несколько миллионов строк.

В общем, хотелось бы услышать от уважаемого сообщества пути решения, советы, уточняющие вопросы и пр., прежде чем мы будем принимать какие-либо решения по бюджету.
...
Рейтинг: 0 / 0
24.12.2015, 10:42:42
    #39136822
Barvinok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
прошу прощения, обсчитался. вроде как должно быть 22 гигабайта, если зависимость линейная. но в этом я не уверен.
...
Рейтинг: 0 / 0
24.12.2015, 10:56:40
    #39136840
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
BarvinokНаверное, PRIMARY KEY по CHAR(34) это плохая идея, но он там единственный гарантированно уникальный идентификатор каждого события.
Сделайте его отображение на SERIAL (кто вообще додумался на таких объёмах делать GUID первичным идентификатором? особенно с учётом того, что в MySQL это приведённый тип, а не базовый).
Кстати, почему два GUID укладываются в CHAR(34), а третий в CHAR(35)?

Barvinokдля последующего анализа
Какого именно анализа?

BarvinokЛог живёт в таблице, вот она в сокращённом виде
Даже сокращённый вид сильно намекает, что архитектор злостно ненавидит нормализацию.
...
Рейтинг: 0 / 0
24.12.2015, 11:18:46
    #39136861
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
AkinaКстати, почему два GUID укладываются в CHAR(34), а третий в CHAR(35)?При том, что для человекочитабельного вида надо 36.

Если уж GUID так необходим, то я бы предложил хранить их в BINARY(16). Это уже экономии примерно 60 байт на запись.

`player_name` надо выносить в отдельную таблицу (хотя она наверняка уже есть), а тут оставлять на нее ссылку. 4-х байтового INT будет достаточно. Это еще до 50 байт экономии. Если это поле идет в паре с `player_guid`, то его выносить в ту же таблицу (правда, походе в нем вообще смысл пропадет).

`loc1_name` и `loc1_guid` - аналогично.

`timestamp_raw` и `timestamp_d` тоже не вижу смысла хранить оба.

`plaintext` тоже внушает большие сомнения. Кто и что там будет писать в столь огромных количествах?
Вероятно, тоже есть смысл вынести в отдельную таблицу.

Если ужимать по максимуму, то остается так:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE TABLE `eventlog` (
	`id` BIGINT(20) UNSIGNED NOT NULL,
	`timestamp_raw` BIGINT UNSIGNED NOT NULL COMMENT 'UNIX epoch in milliseconds',
	`player_id` INT NOT NULL COMMENT 'Event origin name',
	`loc1_id` INT NULL DEFAULT NULL COMMENT 'Loc1 name',
	`event_action` ENUM('CAPTURE','LINK','FIELD','NOLINK','NOFIELD','FRACKER','BEACON') NULL DEFAULT NULL COMMENT 'Event action',
	`plaintext_id` INT COMMENT 'Event plaintext'
)
COMMENT='Global event log'
COLLATE='utf8_general_ci'
ENGINE=MyISAM;

Итого 29 байт на запись. Вместо сотен в исходном варианте.
...
Рейтинг: 0 / 0
24.12.2015, 12:02:05
    #39136934
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
miksoftПри том, что для человекочитабельного вида надо 36.
Это уже мелочи... тем более что тире можно добавить уже на клиенте при форматировании вывода.
...
Рейтинг: 0 / 0
24.12.2015, 13:28:51
    #39137066
Barvinok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
AkinaBarvinokНаверное, PRIMARY KEY по CHAR(34) это плохая идея, но он там единственный гарантированно уникальный идентификатор каждого события.
Сделайте его отображение на SERIAL
а можно про "сделать отображение" ещё раз и как для чайников?

Кстати, почему два GUID укладываются в CHAR(34), а третий в CHAR(35)?
потому что там у гуида есть числовой постфикс, указывающий на его тип - что это гуид события, гуид игрока, гуид локации или ещё чего-то.

Barvinokдля последующего анализаКакого именно анализа?
например: выяснить всю историю действий игрока по его гуиду, выяснить кто, когда и что делал с локацией по её гуиду, всё это в некоторых временных рамках, выяснить даты последних действий определённого типа по всем локациям в определённой области и тому подобное.

(кто вообще додумался на таких объёмах делать GUID первичным идентификатором? особенно с учётом того, что в MySQL это приведённый тип, а не базовый).
BarvinokЛог живёт в таблице, вот она в сокращённом виде
Даже сокращённый вид сильно намекает, что архитектор злостно ненавидит нормализацию.
вы отчасти правы, но я, увы, не архитектор системы.
мы получаем данные из чёрного ящика по апи, в котором они приезжают именно в таком виде.
и да, насчёт timestamp_d согласен, протупил и уберу.
но вот что касается хранения имён и гуидов рядом, то тут особенности:
1) что таблиц соответствия имён гуидам ни для игроков ни для локаций нет; вернее, они-то есть, но генерируются по этому же евентлогу и поэтому заведомо неполны.
2) как игроки, так и локации могут переименовываться и узнавать об этом мы можем только увидев в приходящих из апи данных другое имя при известном гуиде; а для анализа порой бывает важно узнать все предыдущие имена игрока.
имена порталов действительно можно убрать, я думаю.
...
Рейтинг: 0 / 0
24.12.2015, 13:33:22
    #39137074
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Barvinokмы получаем данные из чёрного ящика по апи, в котором они приезжают именно в таком виде.Но это не мешает вам ввести свою нормализацию.
Да, усложнится и замедлится вставка данных. Но уменьшится общий объем и ускорится выборка.
...
Рейтинг: 0 / 0
24.12.2015, 13:39:42
    #39137083
Barvinok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
miksoftAkinaКстати, почему два GUID укладываются в CHAR(34), а третий в CHAR(35)?При том, что для человекочитабельного вида надо 36.
Если уж GUID так необходим, то я бы предложил хранить их в BINARY(16). Это уже экономии примерно 60 байт на запись.
можно рассчитывать на то, что работа с индексами бинарных блобов как-то лучше, чем у строк?

`player_name` надо выносить в отдельную таблицу (хотя она наверняка уже есть), а тут оставлять на нее ссылку
игроки переименовываются :( и стратегически важно знать как все прошлые имена игрока, так и его текущее имя.
надо подумать, как это лучше сделать.

`plaintext` тоже внушает большие сомнения. Кто и что там будет писать в столь огромных количествах?
тут я сначала хотел поставить TINYTEXT, но потом обнаружил, что с очень небольшой вероятностью, но всё же попадаются описания, которые содержат длинные имена игроков и локаций (в описании может быть две локации), да ещё всё это в UTF8, и что в результате оно не влазит в 0xFF символов.

Вероятно, тоже есть смысл вынести в отдельную таблицу.
видимо, да. это малоиспользуемое поле.

Если ужимать по максимуму, то остается так:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE TABLE `eventlog` (
	`id` BIGINT(20) UNSIGNED NOT NULL,
	`timestamp_raw` BIGINT UNSIGNED NOT NULL COMMENT 'UNIX epoch in milliseconds',
	`player_id` INT NOT NULL COMMENT 'Event origin name',
	`loc1_id` INT NULL DEFAULT NULL COMMENT 'Loc1 name',
	`event_action` ENUM('CAPTURE','LINK','FIELD','NOLINK','NOFIELD','FRACKER','BEACON') NULL DEFAULT NULL COMMENT 'Event action',
	`plaintext_id` INT COMMENT 'Event plaintext'
)
COMMENT='Global event log'
COLLATE='utf8_general_ci'
ENGINE=MyISAM;

Итого 29 байт на запись. Вместо сотен в исходном варианте.
ох.
но ведь ищут игроков и локации по гуиду, который не мы задаём, а он является внутриигровым, заложенным в архитектуру игры не нами.
то есть придётся сначала лезть в таблицу гуидов игроков, искать там ид, учитывая возможные переименования, потом то же самое для локаций а потом только основной запрос.
опять же, ощущение оверкилла ради экономии места под хранение данных, которое (место) не является проблемой.
но мы попробуем.
...
Рейтинг: 0 / 0
24.12.2015, 13:43:21
    #39137086
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Barvinokможно рассчитывать на то, что работа с индексами бинарных блобов как-то лучше, чем у строк?BINARY(16) - это не блоб, это та же строка, только которая не подвергается преобразованиям кодировок. Т.е., грубо говоря, это CHAR без кодировки.
...
Рейтинг: 0 / 0
24.12.2015, 13:47:42
    #39137089
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Barvinokигроки переименовываются :( и стратегически важно знать как все прошлые имена игрока, так и его текущее имя.Можно дополнительно к таблице игроков хранить историческую таблицу имен игроков с именем и датой смены (или периодом действия).
...
Рейтинг: 0 / 0
24.12.2015, 13:48:40
    #39137091
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Barvinokтут я сначала хотел поставить TINYTEXT, но потом обнаружил, что с очень небольшой вероятностью, но всё же попадаются описания, которые содержат длинные имена игроков и локаций (в описании может быть две локации), да ещё всё это в UTF8, и что в результате оно не влазит в 0xFF символов.Лимита в 0xFF символов вроде бы нигде нет.
...
Рейтинг: 0 / 0
24.12.2015, 13:54:32
    #39137095
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Barvinokто есть придётся сначала лезть в таблицу гуидов игроков, искать там идДля этого придуманы JOIN-ы.
...
Рейтинг: 0 / 0
24.12.2015, 14:04:38
    #39137106
Barvinok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
miksoftBarvinokтут я сначала хотел поставить TINYTEXT, но потом обнаружил, что с очень небольшой вероятностью, но всё же попадаются описания, которые содержат длинные имена игроков и локаций (в описании может быть две локации), да ещё всё это в UTF8, и что в результате оно не влазит в 0xFF символов.Лимита в 0xFF символов вроде бы нигде нет.
я об этом
http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html
авторTINYTEXT [CHARACTER SET charset_name] [COLLATE collation_name]
A TEXT column with a maximum length of 255 (28 − 1) characters. The effective maximum length is less if the value contains multibyte characters. Each TINYTEXT value is stored using a 1-byte length prefix that indicates the number of bytes in the value.
т.е. у нас там полно всякой кириллицы с иероглифами, и ещё UTF8 поэтому 0xFF мне и показались недостаточными.
...
Рейтинг: 0 / 0
24.12.2015, 14:15:10
    #39137132
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
BarvinokавторTINYTEXT [CHARACTER SET charset_name] [COLLATE collation_name]
A TEXT column with a maximum length of 255 (28 − 1) characters.Ага, понял.
Вопрос-то не в том, "почему TINYTEXT, а не TEXT", а "почему TEXT вместо отдельной таблицы с VARCHAR (или TEXT на худой конец)?"
...
Рейтинг: 0 / 0
24.12.2015, 14:16:31
    #39137136
Barvinok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
miksoftBarvinokможно рассчитывать на то, что работа с индексами бинарных блобов как-то лучше, чем у строк?BINARY(16) - это не блоб, это та же строка, только которая не подвергается преобразованиям кодировок. Т.е., грубо говоря, это CHAR без кодировки.
ну почему же это строка?
вот типичный вид гуида из игры, как он приезжает через апи:
Код: plaintext
7bddc559e95e4aaebbb846dc925962f5.c
здесь 32 шестнадцатеричных символа и ".c" - признак того, что это гуид игрока.
теперь вы предлагаете хранить её как BINARY(16), т.е. это уже строкой перестаёт быть и становится бинарным фрагментом что-ли.
да, это займёт меньше места, но точно ли поиск по бинарным данным лучше чем по строке?
...
Рейтинг: 0 / 0
24.12.2015, 14:18:34
    #39137140
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Barvinokmiksoftпропущено...
BINARY(16) - это не блоб, это та же строка, только которая не подвергается преобразованиям кодировок. Т.е., грубо говоря, это CHAR без кодировки.
ну почему же это строка?
вот типичный вид гуида из игры, как он приезжает через апи:
Код: plaintext
7bddc559e95e4aaebbb846dc925962f5.c
здесь 32 шестнадцатеричных символа и ".c" - признак того, что это гуид игрока.
теперь вы предлагаете хранить её как BINARY(16), т.е. это уже строкой перестаёт быть и становится бинарным фрагментом что-ли.
да, это займёт меньше места, но точно ли поиск по бинарным данным лучше чем по строке?Если индекс начнет влезать в кэш в оперативной памяти, то да, это будет сильно лучше.
...
Рейтинг: 0 / 0
24.12.2015, 14:55:31
    #39137213
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
BarvinokAkinaпропущено...

Сделайте его отображение на SERIAL
а можно про "сделать отображение" ещё раз и как для чайников?
Запросто.

Заводите таблицу
Код: sql
1.
2.
3.
4.
5.
CREATE TABLE guids (
  id SERIAL PRIMARY KEY
, guid VARCHAR(36)
-- , guidtype ENUM('Event', 'Player', 'Location', 'etc')
); 

Гуиды кладёте в неё. А в свои таблицы помещаете вменяемые BIGINTы.
...
Рейтинг: 0 / 0
24.12.2015, 15:02:15
    #39137220
netwind
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Barvinok
но ведь ищут игроков и локации по гуиду, который не мы задаём, а он является внутриигровым, заложенным в архитектуру игры не нами.
то есть придётся сначала лезть в таблицу гуидов игроков, искать там ид, учитывая возможные переименования, потом то же самое для локаций а потом только основной запрос.

А кому сейчас легко ? Эти переименования относительно редко происходят в сравнении с объемом остальных событий.

опять же, ощущение оверкилла ради экономии места под хранение данных, которое (место) не является проблемой.
но мы попробуем.

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


автора можно про "сделать отображение" ещё раз и как для чайников?
Имелся ввиду искусственный первичный ключ с auto_increment.
Формально, по документации, SERIAL определяется как BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE.
Опять же, из стратегических предпосылок, GUID никогда не являлся хорошим выбором для любого ключа.
По-моему, вам вообще GUID события не нужно хранить. Только в каком-то предварительном хранилище в парсере, чтобы избежать дублей и там же отбрасывать. Эти GUID ведь люди не будут смотреть. Люди будут смотреть текст.
Насчет остальных GUID - обсуждаемо.
...
Рейтинг: 0 / 0
24.12.2015, 15:04:04
    #39137221
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Akina
Код: sql
1.
id SERIAL PRIMARY KEY

AUTO_INCREMENT ?
...
Рейтинг: 0 / 0
24.12.2015, 15:48:48
    #39137279
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
miksoft , а что смущает?
...
Рейтинг: 0 / 0
24.12.2015, 16:17:28
    #39137315
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Akina miksoft , а что смущает?Что на тот момент я не нашел в документации слова SERIAL.
Сейчас уже нашел в Numeric Type Overview .
А искал в CREATE TABLE и окрестностях.
...
Рейтинг: 0 / 0
24.12.2015, 17:00:33
    #39137387
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Для меня, кстати, загадка, почему в SERIAL не затолкали до кучи и PRIMARY KEY. Ещё лучше - добавлять его в случае, если в CREATE TABLE описание первичного ключа отсутствует, и не добавлять при наличии. Но это уже фенечки.
...
Рейтинг: 0 / 0
24.12.2015, 17:02:32
    #39137388
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Кстати, подумал, и решил, что правильнее таблица будет в таком виде:
Код: sql
1.
2.
3.
4.
5.
CREATE TABLE guids (
  id SERIAL PRIMARY KEY
, guid VARCHAR(36) NOT NULL UNIQUE
-- , guidtype ENUM('Event', 'Player', 'Location', 'etc') NOT NULL
); 
...
Рейтинг: 0 / 0
24.12.2015, 23:04:22
    #39137698
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
Barvinok,
мужик, MySQL для таких объемов данных не подходит, прежде всего, потому, что невозможно создавать таблицы без индексов, а потом создавать к ним индексы.

тебе нужно использовать InnoDb, потому что myisam полный трэш, и не умеет кэшировать данные вообще, и
тебе ОБЯЗАТЕЛЬНО нужно создать первичный ключ перед загрузкой данных.

а еще лучше просто выкинуть MySQL и заменить его чем то стоящим, хотя бы PG.
...
Рейтинг: 0 / 0
24.12.2015, 23:08:34
    #39137699
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Большая таблица (масштабируемость?)
[quot Barvinok].
Я, в принципе, представляю, почему так происходит.

не, не представляешь даже близко...

Но тогда вопрос - а сколько ему надо? Если там линейная зависимость, то для базы в 400 млн строк ему понадобится, что ли, 55 гигабайт на индексы?


там логарифмическая зависимость

еще раз, MyISAM не используй от слова совсем.
но и с inno это не вдруг заработает.
...
Рейтинг: 0 / 0
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Большая таблица (масштабируемость?) / 25 сообщений из 38, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]