Форум » [x]Harbour » Нужен реально компактный индекс » Ответить

Нужен реально компактный индекс

Sergy: Добрый день. Есть большая таблица (под 100 мегов) - выборка по товару за пару лет с такой структурой: -- code C10 - код товара stock I2 - код склада хранения, 32бита date D3 - дата (компактная форма) remain I4 - остаток товара на эту дату, 64бита sales I4 - продано в этот день, 64 бита -- Чтобы правильно заполнить эту таблицу на основании данных приходов/перемещений/продаж, нужно иметь индекс по "код товара+код склада+дата". Если делать "классически": INDEX ON table->code+STR(table->stock,5)+DTOS(table->date) TO... - получаем: 1) размер индексного файла становится много больше самой таблицы (23 байта индексное выражение против 15 байт одна строка таблицы) 2) после увеличения самой таблицы свыше 20 мегов - скорость добавления в нее падает очень и очень заметно. Таблица и индекс локальны и открыты монопольно. ----- Что я подумал: а существует ли какой-то способ создания индекса на основе имеющихся, "компактных" форм хранения данных? По сути, выражение DTOS() и "приклеенный" STR() дают избыточную сортировку по дате и номеру склада, которые в момент создания этой таблицы не нужны. Нужен быстрый поиск записи по трем полям и корректировка значений. Т.е. нужно "бинарное" значение даты и 32-битного числа. PS: про I2BIN() и BIN2I() знаю с времен Клиппера. Вопрос - что делать с датой в данном случае и с разными "интересными" и "компактными" форматами данных, например, "@", "+" итп... - в общем ? PPS: dbfntx Спасибо.

Ответов - 24, стр: 1 2 All

PSP: Чё-та я не врубился, зачем такие сложности. dbfcdx не пробовал?

Dima: PSP пишет: dbfcdx не пробовал? Да он где то писал , что по каким то причинам он не подходит. Задача локальная и можно было бы прикрутить локальный ADS и юзать индексы IDX.

nick_mi: У меня в некоторых задачах построены индексы NTX по двоичному полю вроде все работает и нареканий не было


alkresin: Dima пишет: Да он где то писал , что по каким то причинам он не подходит. Нет и не может быть таких причин. Что до основного вопроса - можно попробовать изменить формат таблицы - заменить "интересные" типы данных на "C" - утрамбовать с помощью своих функций поля, входящие в индекс. Если размер становится критичным, стоит разбить таблицу на несколько, по годам - учитывая, что со временем она будет расти.

petr707: Не, не нужно. Полагаю, ложный путь. Не приведет к цели. Какая она- ускорение доступа ? Или экономия места на диске ? Возможно, проще изменить архитектуру - перепроектировать размещение данных в таблицах.. Таблица напоминает оперативно модифицируемый агрегатный отчет. Зачем держать данные за два года, меняется наверняка только последний текущий месяц? Возможно, быстрее и проще пересоздавать отчет целиком , чем поддерживать оперативный агрегат.

SergKis: Sergy надо избавиться от вычисления ключа, добавив поле ключа и заполнять его в момент образования записи, дату можно сократить до год(2) и номер дня от начала года, + полученный ключ (символьный) можно пропустить через crc32 и в ключе использовать значение от crc32, но надо посмотреть точнее, может code+str(crc32(...), 8), но это писать в поле KY и индекс простой INDEX ON KY TO ...

SergKis: PS. Даже, доспустив дублирование ключа, можно поменять точный подвод, на относительный - подводим по ключу - do while ищем точное значение на совпадение по реальным значениям полей записи т.е. можно использовать и str(crc16(...), 5)

Sergy: Отвечу по порядку. С планшета, поэтому без цитат, сорри. Почитал я реализацию dbfcdx/dbfntx в Harbour - по внутренней структуре/ограничениям между ними нет разницы. CDX лишь позволяет в одном файле хранить несколько тегов. IDX/ADS - ради одного, пусть "гигантского" отчета прикручивать? Дадут ли они реальное увеличение именно скорости поиска среди миллионов записей? Не уверен, потому что не пробовал. Для повседневной работы с запасом хватает dbfntx. DBFNTX у меня нормально работает с двоичными данными. В данном примере смешаны строка+дата+число Вариант с укороченным индексом - только, например, кода товара и последующим dowhile ... skip enddo - буду пробовать тоже. Может быть, он даст прирост скорости. Спасибо. По структуре данных - не очень понимаю, что такое "оперативно модифицируемый агрегатный расчет". Задача - заполнить таблицу товар/дата/остаток/продано за длительный период - на основании текущих остатков + журналов продаж/приходов/перемещений. Это нужно для анализа работы отдела закупщиков, более грамотного планирования пополнения складских запасов, выявления сезонности товара и тп. Да, обновляться на регулярной основе будут данные за последние дней 10-15, тк именно в них возможны корректировки. Но ведь эти данные еще нужно быстро найти и обновить в таблице, хранящей всю эту информацию. Разбивка на несколько таблиц по годам... Да, возможно придется пойти и по этому пути. Не хотелось-бы, тк реально анализировать более двух-трех лет вряд-ли кому понадобится. Добавление "индексного поля" - мне кажется, один из наиболее реальных способов... Идеально было-бы получить дату в виде строки размером в три байта (в которых она хранится). Но как ? Спасибо.

petr707: Нужны же не все даты, а только за последние 2 года+ вперед на лет 10 ? Тогда просто используйте число дней от 01.01.2010 date_beg := stod('20100101') n:=date_x-date_beg Ну а число дней - паковать

alkresin: Sergy пишет: Почитал я реализацию dbfcdx/dbfntx в Harbour - по внутренней структуре/ограничениям между ними нет разницы. Cdx по определению еще со времен Клиппера - компактный индекс. Впрочем, можете проверить сами. Я вот сейчас построил для сравнения индексы к одной своей таблице: Кол-во записей - 344600 Длина ключа - 14 байт Размер cdx индекса - 1679K Размер ntx индекса - 8617K Идеально было-бы получить дату в виде строки размером в три байта (в которых она хранится). Но как ? Ну, например: Chr(Year(d)-2000)+Chr(Month(d)+Chr(Day(d) Можно и в 2 байта, если кол-во лет ограничено: Chr( (Year(d)-2012)*16 + Month(d) ) + Chr(Day(d))

SergKis: Sergy пишет:получить дату в виде строки размером в три байта если использовать str(crc32(cKey),8), то все равно, как получена дата - хоть словами, для данного примера (важно формировать cKey), для других индексов в других файлах alkresin правНу, например:...

SergKis: Sergy пишет:Вариант с укороченным индексом - только, например, кода товара и последующим dowhile ... skip enddo - буду пробовать я имел ввиду не укороченный код, а поле KY ключ, полученный str(crc32(cKey), 8) или str(crc16(cKey, 5), т.е. длина new поля KY 8 или 5 байт, а алгоритм получения строки cKey вам виднее по задаче

SergKis: alkresin пишет:Нет и не может быть таких причин. если у файла dbf только один индекс (и имя индекса совпадает с dbf), то преобразовать в cdx для начала только его - не должно быть проблеммой: REQUEST DBFCDX в открытие этого файла добавить VIA ... и уже все должно срастись по текстам

petr707: Задача - заполнить таблицу товар/дата/остаток/продано за длительный период - на основании текущих остатков + журналов продаж/приходов/перемещений. А как и когда заполнить ? Однократно по требованию(отдела закупщиков) или держать постоянно готовым, а модифицировать сразу по факту каждой продажи - это пополнение отчета. Упрощенно - факт продажи заносится в базу продаж. Если нужно узнать итоговую сумму продаж за день на текущий момент , создается отчет типа SUM... или TOTAL.. или Dbeval . Получаем SUMDAY Вариант оперативного агрегата - открыто две таблицы - продаж и таблица итога(агрегат). По факту продаж дополнительно к записи в первую таблицу , сумма каждой продажи добавляется к SUMDAY во второй таблице в момент продажи. Иногда морока с обслуживанием второй таблицы(готовый отчет) не стоит свеч. Быстрее и проще по каждому запросу(или по расписанию) заново сделать SUM.. или TOTAL..

Sergy: petr707 пишет: Нужны же не все даты, а только за последние 2 года+ вперед на лет 10 ? Тогда просто используйте число дней от 01.01.2010 date_beg := stod('20100101') n:=date_x-date_beg Ну а число дней - паковать Да, наверное так и сделаю. Дату начала периода сохраню - двух байт для расчета хватит за глаза.

Sergy: alkresin пишет: Cdx по определению еще со времен Клиппера - компактный индекс. Впрочем, можете проверить сами. Я вот сейчас построил для сравнения индексы к одной своей таблице: Кол-во записей - 344600 Длина ключа - 14 байт Размер cdx индекса - 1679K Размер ntx индекса - 8617K 14 байт * 344600 записей = 4'824'400 байт. Что-то не сходится... В любом случае - потестирую CDX

Sergy: petr707 пишет: А как и когда заполнить ? Однократно по требованию(отдела закупщиков) или держать постоянно готовым, а модифицировать сразу по факту каждой продажи - это пополнение отчета. Упрощенно - факт продажи заносится в базу продаж. Если нужно узнать итоговую сумму продаж за день на текущий момент , создается отчет типа SUM... или TOTAL.. или Dbeval . Получаем SUMDAY Вариант оперативного агрегата - открыто две таблицы - продаж и таблица итога(агрегат). По факту продаж дополнительно к записи в первую таблицу , сумма каждой продажи добавляется к SUMDAY во второй таблице в момент продажи. Иногда морока с обслуживанием второй таблицы(готовый отчет) не стоит свеч. Быстрее и проще по каждому запросу(или по расписанию) заново сделать SUM.. или TOTAL.. Планируется раз в неделю пересоздавать полностью, например, за последние 2 года. Далее, каждый день, в 4 утра проводится тех.обслуживание - пересоздание индексов, подчистка мусора, упаковка и тп. В это время думаю делать обновление "агрегата" за, скажем 14 дней. Актуальность изменений в течении рабочего дня не очень важна.

Панченко: Со временем таблица опять увеличится. Не лучше ли, не меняя уже готовой структуры, переносить даныые старше 2-3 лет в архив, а в таблице оставлять только актуальные данные? Это можно делать в начале каждого года, занося в таблицу остатки на 1 яваря. Возможно, тогда вас устроит и уже существующий индекс.

PSP: Sergy пишет: 14 байт * 344600 записей = 4'824'400 байт. Что-то не сходится... Вот поэтому он и называется "компактным" ))

Sergy: PSP пишет: Вот поэтому он и называется "компактным" )) Разобрался. Если он "компактный" на диске - это не значит, что он "компактный" в памяти: https://groups.google.com/forum/#!starred/harbour-users/vDXzEB_Ih8I druzus: CDX format allows to create 4 different types of indexes: 1. single tag noncompressed indexes (def.ext: .idx) 2. single tag compressed indexes (def.ext: .idx) 3. multi tag non-compressed indexes (def.ext: .cdx) 4. multi tag compressed indexes (def.ext: .cdx) Harbour and CL53 DBFCDX (COMIX) support only 4-th format.



полная версия страницы