|
|
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Добрый день! Есть один проект, в рамках которого ведётся лог игровых событий для последующего анализа. Лог живёт в таблице, вот она в сокращённом виде: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. Да, здесь нет индексов, в этом и проблема :( Когда-то недавно, они были - для минимального анализа вот такие Код: sql 1. 2. 3. 4. 5. Но было это до тех пор, пока количество строк не превышало миллиона-двух и всё довольно шустро бегало. Потом нам захотелось загрузить туда всю эпоху глобально и продолжать её отслеживать. Это за 3 прошедших месяца 400 миллионов строк, общим объёмом 145 GiB и плюс к тому ещё около 3-4 миллионов строк ежедневно должно добавляться. Месяцы мы собирали отдельными SQL-файлами с инсертами, потом ужаснувшись скорости их загрузки в базу, загрузили их в клонированные таблицы без ключей, сделали SELECT INTO, потом из основной таблицы сделали LOAD INFILE, при этом в основной таблице пришлось тоже убрать индексы, иначе эта процедура затянулась бы на месяц или больше :(. Теперь да, в единой таблице без индексов 400 миллионов строк и с этим что-то надо делать, т.к. никакие анализаторы не работают без индексов. При попытке их добавить Код: sql 1. я вижу, что сервер начинает довольно бодренько писать временные MYD и MYI, кое-как доползает до отметки в 13 гигабайт MYD и полтора-два MYI и после этого скорость резко падает до черепашьей. Я, в принципе, представляю, почему так происходит. Наверное, PRIMARY KEY по CHAR(34) это плохая идея, но он там единственный гарантированно уникальный идентификатор каждого события. Возможно, дело в том что сервер слабый - там всего 2 гигабайта оперативы и Pentium(R) Dual-Core CPU E5200 @ 2.50GHz. Мы бы даже могли раскошелиться на более мощный сервер, если бы были точно уверены, что проблема именно в этом (что индексы не влазят в key buffer). Но тогда вопрос - а сколько ему надо? Если там линейная зависимость, то для базы в 400 млн строк ему понадобится, что ли, 55 гигабайт на индексы? И нельзя забывать что ежедневно таблица будет расти на несколько миллионов строк. В общем, хотелось бы услышать от уважаемого сообщества пути решения, советы, уточняющие вопросы и пр., прежде чем мы будем принимать какие-либо решения по бюджету. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 10:37 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
прошу прощения, обсчитался. вроде как должно быть 22 гигабайта, если зависимость линейная. но в этом я не уверен. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 10:42 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
BarvinokНаверное, PRIMARY KEY по CHAR(34) это плохая идея, но он там единственный гарантированно уникальный идентификатор каждого события. Сделайте его отображение на SERIAL (кто вообще додумался на таких объёмах делать GUID первичным идентификатором? особенно с учётом того, что в MySQL это приведённый тип, а не базовый). Кстати, почему два GUID укладываются в CHAR(34), а третий в CHAR(35)? Barvinokдля последующего анализа Какого именно анализа? BarvinokЛог живёт в таблице, вот она в сокращённом виде Даже сокращённый вид сильно намекает, что архитектор злостно ненавидит нормализацию. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 10:56 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
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. Итого 29 байт на запись. Вместо сотен в исходном варианте. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 11:18 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
miksoftПри том, что для человекочитабельного вида надо 36. Это уже мелочи... тем более что тире можно добавить уже на клиенте при форматировании вывода. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 12:02 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
AkinaBarvinokНаверное, PRIMARY KEY по CHAR(34) это плохая идея, но он там единственный гарантированно уникальный идентификатор каждого события. Сделайте его отображение на SERIAL а можно про "сделать отображение" ещё раз и как для чайников? Кстати, почему два GUID укладываются в CHAR(34), а третий в CHAR(35)? потому что там у гуида есть числовой постфикс, указывающий на его тип - что это гуид события, гуид игрока, гуид локации или ещё чего-то. Barvinokдля последующего анализаКакого именно анализа? например: выяснить всю историю действий игрока по его гуиду, выяснить кто, когда и что делал с локацией по её гуиду, всё это в некоторых временных рамках, выяснить даты последних действий определённого типа по всем локациям в определённой области и тому подобное. (кто вообще додумался на таких объёмах делать GUID первичным идентификатором? особенно с учётом того, что в MySQL это приведённый тип, а не базовый). BarvinokЛог живёт в таблице, вот она в сокращённом виде Даже сокращённый вид сильно намекает, что архитектор злостно ненавидит нормализацию. вы отчасти правы, но я, увы, не архитектор системы. мы получаем данные из чёрного ящика по апи, в котором они приезжают именно в таком виде. и да, насчёт timestamp_d согласен, протупил и уберу. но вот что касается хранения имён и гуидов рядом, то тут особенности: 1) что таблиц соответствия имён гуидам ни для игроков ни для локаций нет; вернее, они-то есть, но генерируются по этому же евентлогу и поэтому заведомо неполны. 2) как игроки, так и локации могут переименовываться и узнавать об этом мы можем только увидев в приходящих из апи данных другое имя при известном гуиде; а для анализа порой бывает важно узнать все предыдущие имена игрока. имена порталов действительно можно убрать, я думаю. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 13:28 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Barvinokмы получаем данные из чёрного ящика по апи, в котором они приезжают именно в таком виде.Но это не мешает вам ввести свою нормализацию. Да, усложнится и замедлится вставка данных. Но уменьшится общий объем и ускорится выборка. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 13:33 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
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. Итого 29 байт на запись. Вместо сотен в исходном варианте. ох. но ведь ищут игроков и локации по гуиду, который не мы задаём, а он является внутриигровым, заложенным в архитектуру игры не нами. то есть придётся сначала лезть в таблицу гуидов игроков, искать там ид, учитывая возможные переименования, потом то же самое для локаций а потом только основной запрос. опять же, ощущение оверкилла ради экономии места под хранение данных, которое (место) не является проблемой. но мы попробуем. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 13:39 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Barvinokможно рассчитывать на то, что работа с индексами бинарных блобов как-то лучше, чем у строк?BINARY(16) - это не блоб, это та же строка, только которая не подвергается преобразованиям кодировок. Т.е., грубо говоря, это CHAR без кодировки. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 13:43 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Barvinokигроки переименовываются :( и стратегически важно знать как все прошлые имена игрока, так и его текущее имя.Можно дополнительно к таблице игроков хранить историческую таблицу имен игроков с именем и датой смены (или периодом действия). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 13:47 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Barvinokтут я сначала хотел поставить TINYTEXT, но потом обнаружил, что с очень небольшой вероятностью, но всё же попадаются описания, которые содержат длинные имена игроков и локаций (в описании может быть две локации), да ещё всё это в UTF8, и что в результате оно не влазит в 0xFF символов.Лимита в 0xFF символов вроде бы нигде нет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 13:48 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Barvinokто есть придётся сначала лезть в таблицу гуидов игроков, искать там идДля этого придуманы JOIN-ы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 13:54 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
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 мне и показались недостаточными. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 14:04 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
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 на худой конец)?" ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 14:15 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
miksoftBarvinokможно рассчитывать на то, что работа с индексами бинарных блобов как-то лучше, чем у строк?BINARY(16) - это не блоб, это та же строка, только которая не подвергается преобразованиям кодировок. Т.е., грубо говоря, это CHAR без кодировки. ну почему же это строка? вот типичный вид гуида из игры, как он приезжает через апи: Код: plaintext теперь вы предлагаете хранить её как BINARY(16), т.е. это уже строкой перестаёт быть и становится бинарным фрагментом что-ли. да, это займёт меньше места, но точно ли поиск по бинарным данным лучше чем по строке? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 14:16 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Barvinokmiksoftпропущено... BINARY(16) - это не блоб, это та же строка, только которая не подвергается преобразованиям кодировок. Т.е., грубо говоря, это CHAR без кодировки. ну почему же это строка? вот типичный вид гуида из игры, как он приезжает через апи: Код: plaintext теперь вы предлагаете хранить её как BINARY(16), т.е. это уже строкой перестаёт быть и становится бинарным фрагментом что-ли. да, это займёт меньше места, но точно ли поиск по бинарным данным лучше чем по строке?Если индекс начнет влезать в кэш в оперативной памяти, то да, это будет сильно лучше. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 14:18 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
BarvinokAkinaпропущено... Сделайте его отображение на SERIAL а можно про "сделать отображение" ещё раз и как для чайников? Запросто. Заводите таблицу Код: sql 1. 2. 3. 4. 5. Гуиды кладёте в неё. А в свои таблицы помещаете вменяемые BIGINTы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 14:55 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Barvinok но ведь ищут игроков и локации по гуиду, который не мы задаём, а он является внутриигровым, заложенным в архитектуру игры не нами. то есть придётся сначала лезть в таблицу гуидов игроков, искать там ид, учитывая возможные переименования, потом то же самое для локаций а потом только основной запрос. А кому сейчас легко ? Эти переименования относительно редко происходят в сравнении с объемом остальных событий. опять же, ощущение оверкилла ради экономии места под хранение данных, которое (место) не является проблемой. но мы попробуем. В долговременном плане, размер данных является проблемой. Чем меньше размер полей, тем быстрее создание индексов бы отработало. Выборки и сортировки быстрее. Это одна из стратегических целей традиционной нормализации БД. автора можно про "сделать отображение" ещё раз и как для чайников? Имелся ввиду искусственный первичный ключ с auto_increment. Формально, по документации, SERIAL определяется как BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE. Опять же, из стратегических предпосылок, GUID никогда не являлся хорошим выбором для любого ключа. По-моему, вам вообще GUID события не нужно хранить. Только в каком-то предварительном хранилище в парсере, чтобы избежать дублей и там же отбрасывать. Эти GUID ведь люди не будут смотреть. Люди будут смотреть текст. Насчет остальных GUID - обсуждаемо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 15:02 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Akina Код: sql 1. AUTO_INCREMENT ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 15:04 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
miksoft , а что смущает? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 15:48 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Akina miksoft , а что смущает?Что на тот момент я не нашел в документации слова SERIAL. Сейчас уже нашел в Numeric Type Overview . А искал в CREATE TABLE и окрестностях. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 16:17 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Для меня, кстати, загадка, почему в SERIAL не затолкали до кучи и PRIMARY KEY. Ещё лучше - добавлять его в случае, если в CREATE TABLE описание первичного ключа отсутствует, и не добавлять при наличии. Но это уже фенечки. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 17:00 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Кстати, подумал, и решил, что правильнее таблица будет в таком виде: Код: sql 1. 2. 3. 4. 5. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 17:02 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
Barvinok, мужик, MySQL для таких объемов данных не подходит, прежде всего, потому, что невозможно создавать таблицы без индексов, а потом создавать к ним индексы. тебе нужно использовать InnoDb, потому что myisam полный трэш, и не умеет кэшировать данные вообще, и тебе ОБЯЗАТЕЛЬНО нужно создать первичный ключ перед загрузкой данных. а еще лучше просто выкинуть MySQL и заменить его чем то стоящим, хотя бы PG. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 23:04 |
|
||
|
Большая таблица (масштабируемость?)
|
|||
|---|---|---|---|
|
#18+
[quot Barvinok]. Я, в принципе, представляю, почему так происходит. не, не представляешь даже близко... Но тогда вопрос - а сколько ему надо? Если там линейная зависимость, то для базы в 400 млн строк ему понадобится, что ли, 55 гигабайт на индексы? там логарифмическая зависимость еще раз, MyISAM не используй от слова совсем. но и с inno это не вдруг заработает. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.12.2015, 23:08 |
|
||
|
|

start [/forum/topic.php?fid=47&tid=1832332]: |
0ms |
get settings: |
5ms |
get forum list: |
12ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
172ms |
get topic data: |
6ms |
get forum data: |
1ms |
get page messages: |
36ms |
get tp. blocked users: |
1ms |
| others: | 203ms |
| total: | 440ms |

| 0 / 0 |
