|
|
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
Добрый день. Мне нужна консультация по архитектуре. Короткая формулировка вопроса : При SELECT по первичному ключу имеет ли значение размер таблицы? Подробное описание проблемы : Есть таблица на 10 Гб. CREATE TABLE actions ( user_uni INT NOT NULL, project_id INT NOT NULL, action_time INT, status SMALLINT ) Первичный ключ составной: user_uni, project_id Нужно постоянно проверять выполнил ли пользователь user_uni действие по проекту project_id. Есть вариант разбить таблицу на две actions (1-2 ГБ) и actions_history (8-9 ГБ), где actions будет хранить только действия по актуальным проектам, а actions_history - действия по проектам, которые на данный момент закрыты. Я не сомневался бы в правильности этого решения, но есть один нюанс: закрытый проект может быть открыт заново. В случае если проект будет открыт заново (а это происходит регулярно) нужно перенести данные из actions_history в actions, а это может быть от 1000 до 100000 строк. INSERT 100000 строк в одну таблицу и DELETE 100000 из другой таблицы существенная нагрузка. Возникает вопрос: а имеет ли смысл разделение на две таблицы? Спасибо за ваше внимание. Буду благодарен за любые советы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 14:34 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
commanddotcomINSERT 100000 строк в одну таблицу и DELETE 100000 из другой таблицы существенная нагрузка. А если произойдет сбой, то вообще беда: дубль первичного ключа и обратно данные уже не вернуться. Надо делать транзакцию и иммитировать INSERT IGNORE, а это дополнительный расход ресурсов и повышение вероятности отказа сервера. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 14:37 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
commanddotcom, решение с переносом кучек туда--сюда конечно негодное. если удастся разбить партиции так, чтобы перенос в архив и обратно происходил без delete/insert (а только ALTER TABLE partXXX NO INHERIT xxx ; ALTER TABLE partXXX INHERIT yyy;) -- то возможно такое партицирование будет уместно. (хотя там есть подводный камень неприятного размера прямо в архитектуре пж -- куча запросов может в момент этого самого NO INHERIT взбрыкнуть с ошибкой. и это -- не лечится [а гурья не чешутся, и даже не собираются]). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 14:44 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
commanddotcomЕсть таблица на 10 Гб. CREATE TABLE actions ( user_uni INT NOT NULL, project_id INT NOT NULL, action_time INT, status SMALLINT ) за счет чего 10 гигов,или это не вся структура ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 15:02 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
ПЕНСИОНЕРКАcommanddotcomЕсть таблица на 10 Гб. пропущено... за счет чего 10 гигов,или это не вся структура 30 млн записей ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 15:03 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
commanddotcom, Можно выиграть в размере индекса, если сделать условный индекс Предположим, что активный проект имеет статус = 0, тогда: Код: plsql 1. Если активных проектов мало, то выборка будет довольно эффективной ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 15:21 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
tadmincommanddotcom, Можно выиграть в размере индекса, если сделать условный индекс Предположим, что активный проект имеет статус = 0, тогда: Код: plsql 1. Если активных проектов мало, то выборка будет довольно эффективной Так project_id,user_uni все равно первичный ключ. Вы его убрать предлагаете? Развивая Вашу мысль я могу добавить поле project_status SMALLINT и в момент когда проект закрыт делать UPDATE для этого поля при изменении типа кампании на "открыт"\"закрыт". Ну, и соответственно индекс: Код: plsql 1. Запрос SELECT типа Код: plsql 1. Но будет ли движек PostgreSQL использовать этот индекс, если все равно есть первичный ключ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 15:28 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
commanddotcomДобрый день. Мне нужна консультация по архитектуре. Короткая формулировка вопроса : При SELECT по первичному ключу имеет ли значение размер таблицы? Подробное описание проблемы : Есть таблица на 10 Гб. CREATE TABLE actions ( user_uni INT NOT NULL, project_id INT NOT NULL, action_time INT, status SMALLINT ) Первичный ключ составной: user_uni, project_id Нужно постоянно проверять выполнил ли пользователь user_uni действие по проекту project_id. Есть вариант разбить таблицу на две actions (1-2 ГБ) и actions_history (8-9 ГБ), где actions будет хранить только действия по актуальным проектам, а actions_history - действия по проектам, которые на данный момент закрыты. Я не сомневался бы в правильности этого решения, но есть один нюанс: закрытый проект может быть открыт заново. В случае если проект будет открыт заново (а это происходит регулярно) нужно перенести данные из actions_history в actions, а это может быть от 1000 до 100000 строк. INSERT 100000 строк в одну таблицу и DELETE 100000 из другой таблицы существенная нагрузка. Возникает вопрос: а имеет ли смысл разделение на две таблицы? Спасибо за ваше внимание. Буду благодарен за любые советы. Мой совет - да 100% имеет смысл. Просто потому что actions на 1-2Gb будет эффективно кешироваться в памяти базы а вот общая таблица с историей - далеко не факт (и скорее всего в таблицу истории особо никто ходить не будет). А перекинуть 100.000 строк в транзакции не такая уж большая проблема если это делается редко. -- Maxim Boguk www.postgresql-consulting.ru ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 15:43 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
tadmin, Я поддерживаю решение с частичным индексом, я бы предпочел такое решение партиционированию. Частичный индекс при частом использовании будет всегда горячим, как и та часть таблицы, которую он охватывает. Если вы не будете в запросе выбирать не-индексируемые колонки, то возможно и IOS будет случаться. Первичный ключ — это в первую очередь средство контроля целостности, наличие индекса является результатом физической реализации. Он должен быть и точка. У вас есть частый запрос, исходите от него. Если предикаты запроса высокой селективности — стройте дополнительный индекс по всем полям. Если какое-то поле малой селективности (тот же статус), то постройте частичный индекс. PostgreSQL принимает решение о том, какой индекс выгоднее, в первую очередь исходя из размеров индекса. Гадать тут смысла нет — сделайте дамп ваших таблиц, загрузите в тестовую базу, постройте индексы, сделайте партиционирование. И сравните скорость исполнения запросов для разных решений. На основании тестов принимайте решение. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 19:09 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
condomotsosadom, количество операций при доступе по btree-индексу зависит от глубины/высоты индекса, которая зависит логарифмически от количества записей. то есть, разница 100k и 100m отсутствует или ничтожно мала. с другой стороны, не стоит игнорироавать такой фактор, как попадание страницы индекса в кеш. при интенсивной работе по всем значениям потери на невлезающем в кеш индексе будут существенны. что же по общему подходу, для отслеживания изменений вместо периодического опроса нужно использовать нотификацию через очередь и другие push-механизмы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 19:34 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
vyegorovЯ поддерживаю решение с частичным индексом, я бы предпочел такое решение партиционированию.... С индексом проблемы нет. Доступ собственно к индексу должен быть примерно одинаков А вот про саму таблицу "не все так очевидно" ( C ) дочь офицера Встречался с ситуациями, когда приложение выбирало большое кол-во данных из таблице по индексу и, похоже, начинал влиять такой фактор как фрагментация данных в таблице. Т.е., выбираем 1000 коротких записей по конкретному пользователю, но из-за того, что они создавались в разное время и в вперемешку с чужими записями, фактически вычитываем 1000 блоков БД. Получаем 1000 случайных IO операций которые стоят колом на системе хранения. Таблица была большая ( > 40-50 Gb) т.ч. надежды на кеширование не было + из-за той же фрагментации, фактически вся таблица была "горячая". Т.ч. никакого эффекта "будет всегда горячим, как и та часть таблицы, которую он охватывает" не было и в помине. На Oracle вылечилось созданием мега-индекса, где были перечислены все необходимые для запроса поля. Доступ начал происходит к отсортированной информации, кол-во считывание блоков с диска для запросов упало на порядки (ускорение было в 100-ни раз, десятки минут -> секунды). Возможно, более "грамотным" решением на Oracle были бы Index organized table или partition, но создание мега-широкого индекса показалось предпочтительнее (по тестам, индех организованные таблицы крайне странно работали с точки зрения производительности). авторМой совет - да 100% имеет смысл. Просто потому что actions на 1-2Gb будет эффективно кешироваться в памяти базы а вот общая таблица с историей - далеко не факт (и скорее всего в таблицу истории особо никто ходить не будет). плюсуюсь. На этом действительно можно сильно выиграть (а может и нет, все зависит от Ваших данных и запросов). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2015, 19:52 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
Мнения разделились... Окей, спасибо всем отписавшимся за мысли и идеи. Потестирую варианты и "будем посмотреть", как говорят в Одессе. В истории с двумя таблицами меня больше всего целостность данных беспокоит. Первичный ключ действует в рамках таблицы. INSERT IGNORE нет. Одна строка загуляла каким-то образом (такое может быть только вследствие сбоя) не в ту таблицу и вся транзакция псу под хвост. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 00:53 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
vyegorov, авторкак и та часть таблицы, которую он охватывает Вы не учитываете один важный факт - данные делятся на горячие и холодные на уровне строк, а кеширование идет на уровне 8kb страниц. Никакого разумного метода обеспечить локализацию горячих данных в заданных страницах нет, скорее всего в этой задаче горячие строки будут раскиданы случайно по таблице (так как это не insert only таблица-лог где все свежие данные автоматом попадают в конец файла). Обычно это приводит к тому что вместо 1GB горячих данных и 10GB холодных на выходе получается 11GB холодных данных, и все работает медленно и печально. Вообще разделение на уровне таблиц горячих(текущих) и холодных(архивных) данных там где это возможно по бизнес логике это одна из моих стандартных рекомендаций для таблиц размером больше 10GB (особенно если не использовать SSD диски). PS: это не относится к ситуациям когда база заведомо помещается в память, хотя как правило базы растут быстрее чем память которую можно поставить в сервер и со временем всеравно начинаются обращения к диску. -- Maxim Boguk www.postgresql-consulting.ru ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 05:12 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
commanddotcom, сколько проектов всего сколько из них "активных" ? какова частота и глубина возврата в активные ? не просматривали сегментацию по диапазонам project_id ? (оно же-- будет чеками для планировщика). для активации апдейтом (статуса проекта) надо отапдейтить столько же записей, как и для активации перемещением. т.ч. овчинка интересная, но выделки, похоже, не стоит. история с перемещением тоже кривая -- нет констрайнта для планировщика -- как минимум страницу индекса истории придется поднимать . если же project_id изрядно попутаются -- то и больше. т.ч. тоже пуля из той ещё субстанции получается. "нет в шизне щастя" ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 10:40 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
Короткая формулировка вопроса : При SELECT по первичному ключу имеет ли значение размер таблицы? нет, практически не имеет. Подробное описание проблемы : Есть таблица на 10 Гб. Мерий таблицы не объемом в байтах, а количеством строк. Есть вариант разбить таблицу на две actions (1-2 ГБ) и actions_history (8-9 ГБ), где actions будет хранить только действия по актуальным проектам, а actions_history - действия по проектам, которые на данный момент закрыты. пока не вижу смысла. лучше тогда использовать партицирование по времени, разобрать на ччто то типа 100 пермский, тогда может будет толку больше... Я не сомневался бы в правильности этого решения, но есть один нюанс: закрытый проект может быть открыт заново. В случае если проект будет открыт заново (а это происходит регулярно) нужно перенести данные из actions_history в actions, а это может быть от 1000 до 100000 строк. INSERT 100000 строк в одну таблицу и DELETE 100000 из другой таблицы существенная нагрузка. 1000 небольшая, став тысяч уже конечно хуже. Возникает вопрос: а имеет ли смысл разделение на две таблицы? сколько записей всего и будет в разделенных таблицах? пока я бы не делил... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2015, 07:23 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
Maxim BogukcommanddotcomДобрый день. Мне нужна консультация по архитектуре. Короткая формулировка вопроса : При SELECT по первичному ключу имеет ли значение размер таблицы? Подробное описание проблемы : Есть таблица на 10 Гб. пропущено... Первичный ключ составной: user_uni, project_id Нужно постоянно проверять выполнил ли пользователь user_uni действие по проекту project_id. Есть вариант разбить таблицу на две actions (1-2 ГБ) и actions_history (8-9 ГБ), где actions будет хранить только действия по актуальным проектам, а actions_history - действия по проектам, которые на данный момент закрыты. Я не сомневался бы в правильности этого решения, но есть один нюанс: закрытый проект может быть открыт заново. В случае если проект будет открыт заново (а это происходит регулярно) нужно перенести данные из actions_history в actions, а это может быть от 1000 до 100000 строк. INSERT 100000 строк в одну таблицу и DELETE 100000 из другой таблицы существенная нагрузка. Возникает вопрос: а имеет ли смысл разделение на две таблицы? Спасибо за ваше внимание. Буду благодарен за любые советы. Мой совет - да 100% имеет смысл. Просто потому что actions на 1-2Gb будет эффективно кешироваться в памяти базы а вот общая таблица с историей - далеко не факт (и скорее всего в таблицу истории особо никто ходить не будет). А перекинуть 100.000 строк в транзакции не такая уж большая проблема если это делается редко. -- Maxim Boguk www.postgresql-consulting.ru Максим, так части одной таблицы тоже будут эффективно кэшироваться в памяти, нужные оставаться, ненужные уходить... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2015, 07:26 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
vyegorov, PostgreSQL принимает решение о том, какой индекс выгоднее, в первую очередь исходя из размеров индекса. это не так. не из размера индекса, а из его селективности по данному условию. т.е. индекс может быть и большой, но если он отбирает 1 запись из 30 миллионов, он будет использоваться. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2015, 07:32 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
commanddotcomПЕНСИОНЕРКАпропущено... за счет чего 10 гигов,или это не вся структура 30 млн записей это не очень и много, пробуй пока так, без партицирования и без разделения на две таблицы. фактор кэширования конечно важен, но не настолько, чтобы быть решающим. решающий фактор - использование индексов. еще один решающий фактор - правильная архитектура приложения и бд, а с этим я пока не уверен, что все в порядке ( но и что проблемы есть тоже не могу сказать) . пока немного смущает, что таблица узкая, а записей в ней много... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2015, 07:50 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
MasterZivпока немного смущает, что таблица узкая, а записей в ней много... меня тоже смутило именно это, что сама узкая таблица информации по-сути не несет ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2015, 07:55 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
commanddotcom, CREATE TABLE actions ( user_uni INT NOT NULL, project_id INT NOT NULL, action_time INT, status SMALLINT ) - ну странная таблица.... атрибутов мало, почему action_time - целое число? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2015, 07:55 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
MasterZivМаксим, так части одной таблицы тоже будут эффективно кэшироваться в памяти, нужные оставаться, ненужные уходить... Кешируется вся страница 8kb целиком а не отдельные строки. При вышеописанном режиме использования скорее всего на средней 8kb странице в таблице будет 10% нужных данных и 90% архивных (так как я не вижу ни одной причины почему бы не-архивным данным как то кластеризоваться на уровне страниц данных). Собственно деление таблицы на две как раз призвано устранить эту неэффективность в таком случае. -- Maxim Boguk www.postgresql-consulting.ru ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2015, 09:59 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
Maxim BogukMasterZivМаксим, так части одной таблицы тоже будут эффективно кэшироваться в памяти, нужные оставаться, ненужные уходить... При вышеописанном режиме использования скорее всего на средней 8kb странице в таблице будет 10% нужных данных и 90% архивных (так как я не вижу ни одной причины почему бы не-архивным данным как то кластеризоваться на уровне страниц данных). Собственно деление таблицы на две как раз призвано устранить эту неэффективность в таком случае. А может периодический CLUSTER тут поможет? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2015, 11:49 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
vyegorovMaxim Bogukпропущено... При вышеописанном режиме использования скорее всего на средней 8kb странице в таблице будет 10% нужных данных и 90% архивных (так как я не вижу ни одной причины почему бы не-архивным данным как то кластеризоваться на уровне страниц данных). Собственно деление таблицы на две как раз призвано устранить эту неэффективность в таком случае. А может периодический CLUSTER тут поможет? cluster упорядочивает данные в порядке индекса, так что да при правильном выборе индекса cluster поможет. Я бы сказал надо cluster по (project_id) если его делать достаточно часто (достаточно - определяется тем насколько много в таблицу пишут нового и насколько часто ее обновляют). Но CLUSTER намертво блокирует таблицу на время работы. -- Maxim Boguk www.postgresql-consulting.ru ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2015, 12:40 |
|
||
|
Одна большая таблица или две разных
|
|||
|---|---|---|---|
|
#18+
vyegorovА может периодический CLUSTER тут поможет? CLUSTER не подходит, я думаю. Постоянно идет запись. MasterZivпока немного смущает, что таблица узкая, а записей в ней много... атрибутов мало, почему action_time - целое число? 1) Обычная таблица отношений "многие ко многим". Не вижу ничего странного. 2) По action_time выборки нет и не будет. Вот такой я человек - храню время в unixtimestamp. --- Если кому интересно на чем я остановился: Сравнил это 17508603 решение и разделение на две таблицы. При разделении на две таблицы расход ОЗУ меньше почти в 10 раз, но со скачками при переносе данных из таблицы в таблицу. В общем, решил остановиться пока на этом варианте. Перенос обернул в транзакцию и на всякий случай заранее написал утил для восстановление целостности первичного ключа на случай сбоя. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2015, 13:43 |
|
||
|
|

start [/forum/topic.php?fid=53&msg=38934930&tid=1998041]: |
0ms |
get settings: |
6ms |
get forum list: |
15ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
66ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
73ms |
get tp. blocked users: |
1ms |
| others: | 201ms |
| total: | 380ms |

| 0 / 0 |
