Firebird, group by и временные файлы
Apr. 23rd, 2013 07:16 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Покопался в исходниках Firebird (2.5.2) на тему размеров временных файлов.
В итоге, там картина примерно такая:
* Запрос с условием и group by, входной датасет - десятки миллионов записей, результатирующий датасет - 150000 записей, размер записи порядка 150 байт (varchar расширены до максимального размера).
* Для выполнения запроса, подпадающие под условие записи (десятки миллионов) пишутся в сортировщик, затем досортировываются и выгребаются из него в правильном порядке с вычислением аггрегатов.
* Сортировщик реализован поверх временного хранилища данных, которое в свою очередь представляет последовательность блоков размером 1 мб, поначалу находящихся в памяти, а по мере превышения порога (8 МБ по умолчанию для классик-сервера) - записываемых во временные файлы. По виду это все крайне напоминает самодельную реализацию pagefile.
* Временные файлы расширяются кусками по 64 мб, с записью 262144 байтных буферов с нулями в эти куски.
Что здесь очень мне не нравится - это то, что обмен с временными файлами в принципе не выровнен по границам блоков диска, а является кратным размеру записи. Вот, например, из отладочного лога TempSpace::write: 2898976500 1048500
Второе - по-моему, конкретно для данного случая положить готовый результат group by в памяти в виде какого-нибудь дерева поиска и считать аггрегаты на ходу в него было бы гораздо эффективнее, чем долбится в i/o. Фактически мы при запросе читаем всю таблицу, пишем часть прочитанного в временный файл, потом сортируем, потом читаем обратно.
Но, возможно, нету эффективных способов отличить небольшой размер результата от большого размера, который эффективнее делать через сортировку.
В итоге, там картина примерно такая:
* Запрос с условием и group by, входной датасет - десятки миллионов записей, результатирующий датасет - 150000 записей, размер записи порядка 150 байт (varchar расширены до максимального размера).
* Для выполнения запроса, подпадающие под условие записи (десятки миллионов) пишутся в сортировщик, затем досортировываются и выгребаются из него в правильном порядке с вычислением аггрегатов.
* Сортировщик реализован поверх временного хранилища данных, которое в свою очередь представляет последовательность блоков размером 1 мб, поначалу находящихся в памяти, а по мере превышения порога (8 МБ по умолчанию для классик-сервера) - записываемых во временные файлы. По виду это все крайне напоминает самодельную реализацию pagefile.
* Временные файлы расширяются кусками по 64 мб, с записью 262144 байтных буферов с нулями в эти куски.
Что здесь очень мне не нравится - это то, что обмен с временными файлами в принципе не выровнен по границам блоков диска, а является кратным размеру записи. Вот, например, из отладочного лога TempSpace::write: 2898976500 1048500
Второе - по-моему, конкретно для данного случая положить готовый результат group by в памяти в виде какого-нибудь дерева поиска и считать аггрегаты на ходу в него было бы гораздо эффективнее, чем долбится в i/o. Фактически мы при запросе читаем всю таблицу, пишем часть прочитанного в временный файл, потом сортируем, потом читаем обратно.
Но, возможно, нету эффективных способов отличить небольшой размер результата от большого размера, который эффективнее делать через сортировку.
no subject
Date: 2013-04-23 04:22 pm (UTC)no subject
Date: 2013-04-23 04:26 pm (UTC)Проблема в том, что классик-сервер создает по процессу на каждого юзера и если туда поставить хотя бы немного осмысленный лимит памяти - на серваке после 2-3 юзеров кончится память :)
no subject
Date: 2013-04-23 04:37 pm (UTC)no subject
Date: 2013-04-23 04:52 pm (UTC)при этом вопрос о "как кэшировать/аллоцировать замапленое" решает ОС и, по идее, решает кошерно.
no subject
Date: 2013-04-23 04:50 pm (UTC)no subject
Date: 2013-04-23 04:53 pm (UTC)no subject
Date: 2013-04-23 04:58 pm (UTC)no subject
Date: 2013-04-23 05:33 pm (UTC)no subject
Date: 2013-04-23 04:28 pm (UTC)(или хотя бы в более приличном sql)
no subject
Date: 2013-04-23 04:33 pm (UTC)На данный момент будет быстрее сделать мемоизацию результатов запросов с проверками на валидность, чуть-чуть подкрутить размеры сортировочных записей и прочую оптимизацию, чем мигрировать на другую СУБД.
no subject
Date: 2013-04-23 04:37 pm (UTC)no subject
Date: 2013-04-23 04:47 pm (UTC)У меня уже с сервером были проблемы, когда там кончалась память, от чего все дохло с концами. Но это проблема не столько в FB, сколько в том, что это запущено в не совсем вменяемом окружении.
no subject
Date: 2013-04-23 10:16 pm (UTC)no subject
Date: 2013-04-24 05:49 am (UTC)По моим представлениям, это не критично, оверхед минимален. Главное, чтобы размер однократно читаемого куска был побольше, а число чтений соответственно — поменьше.
no subject
Date: 2013-04-24 06:22 am (UTC)no subject
Date: 2013-04-25 10:03 am (UTC)Это называется Sort-based group by.
* Сортировщик реализован поверх временного хранилища данных, которое в свою очередь представляет последовательность блоков размером 1 мб, поначалу находящихся в памяти, а по мере превышения порога (8 МБ по умолчанию для классик-сервера) - записываемых во временные файлы.
Это есть в любой СУБД
> По виду это все крайне напоминает самодельную реализацию pagefile.
Именно так, и только так и можно работать.
> Временные файлы расширяются кусками по 64 мб, с записью 262144 байтных буферов с нулями в эти куски.
Угу
no subject
Date: 2013-04-25 10:09 am (UTC)no subject
Date: 2013-04-25 10:05 am (UTC)это называется Hash Group By. Для него нужно, чтобы ключи влезли в память, и нифига не факт, что они лезут.
Впрочем, это уже фундаментальная проблема любой СУБД - сделать правильный estimate для row count, и на основе этой информации выбрать между sort, hash и index алгоритмами
no subject
Date: 2013-04-25 10:06 am (UTC)Ребе, вы сами всё поняли! В данном случае нужно знать unique cardinality по некоторому ключу.
Если у вас по этому ключи есть B-Tree индекс - estimate сделать легко, а вот если нету - сосите хуй. СУБД в такой ситуции работает по пессимистичному сценарию, и это правильно.
Другой вопрос в том, что можно научить её обучаться по итогам выполнения запросов.