Имя: Пароль:
1C
1C 7.7
v7: Файлы dbf, ключи, индексы
0 BalBess
 
23.05.16
10:47
Кто силен в dbf подскажите (в поисковиках не нашел реальных примеров)
Задача следующая:
Есть dbf - таблица, с 2 полями: товар и цена
нужно отобрать из нее товары с определенной ценой, например 100р
Есть метод Найти(), но как я понял ищет одну (первую) запись, а как найти все записи по условию?
1 Mikeware
 
23.05.16
10:50
НайтиПоКлючу, а дальше перебирать, пока не конец файла.
Это если чисто дибейсик
2 lubitelxml
 
23.05.16
10:51
загрузи в тз и разбери ее как тебе надо
3 Mikeware
 
23.05.16
10:53
(2) зачем лишние телодвижения? индексированный дбф и так достаточно быстр...
4 BalBess
 
23.05.16
10:58
(1) а нет примерчика, не разу с dbf не работал
в СП написано: "Найти запись по индексу". (Запись - в единственном числе), и еще
"Перед вызовом метода следует установить значения всех атрибутов агрегатного объекта типа ''Ключ'', которые участвуют в вычислении выражения текущего индекса."
Эта фраза вообще не понятна, для меня

(2) мне как раз надо наоборот, через ТЗ долго
(3) поле цена у меня индексное
предлагаете просто перебором?

ДБФ.Первая();
Пока 1 = 1 Цикл
    Если ДБФ.Следующая() = 0 Тогда
        Прервать;
    КонецЕсли;

    Если ДБФ.PRICE <> Цена Тогда
        Продолжить;            
    КонецЕсли;
    Сообщить(ДБФ.NAME);
КонецЦикла;

так работает, но я думал через ключи/индексы будет намного быстрее
5 BalBess
 
23.05.16
11:02
Опишу задачу, кассир вводит в поле "цена" - цену
Нужно чтобы по нажатию каждой кнопки, чтобы перезаполнялась таблица. Т.е. в реальном режиме, а товаров около 40000

Я пробовал, через перебор/удаление не нужных позиций из ТЗ уходит 300мс, через цикл по dbf - и заполнение ТЗ заново - где-то 100мс
Хочу еще сократить это время, т.к. компы на кассах "не шустрые"
6 ДенисЧ
 
23.05.16
11:05
Анафея каждый раз читать весь файл? Загрузить и оперировать им не?
7 BalBess
 
23.05.16
11:11
(6) загружается dbf файл один раз, при запуске 1с
Как им "оперировать"? как найти ВСЕ записи по условию (например цене)
8 Mikeware
 
23.05.16
11:13
ДБФ.ДобавитьИндекс("Price","Price",0,0)
ДБФ.Price=1000
Если ДБФ.НайтиПоКлючу(1) тогда
ДБФ.ХХХ - первая запись с равным или больше ключом
пока ДБФ.ВКонце()=0 цикл
   ДБФ.ХХХ - остальные записи с равным или больше ключом
9 Mikeware
 
23.05.16
11:17
+(8) Пардон...
ДБФ.КЛЮЧ.Price=1000
10 BalBess
 
23.05.16
11:22
(8) сорри конечно, но до меня не доходит, как теперь достать все записи из него
что значит ДБФ.ХХХ
11 BalBess
 
23.05.16
11:28
Еще просит перед использованием индекса указать индекс, т.е. пока такая конструкция получилась

ДБФ.ДобавитьИндекс("IDXPRICE","PRICE",0,0)
    
ДБФ.ТекущийИндекс("IDXPRICE");

ДБФ.КЛЮЧ.PRICE=Цена;
    
Если ДБФ.НайтиПоКлючу(0) > 0 тогда
//        ДБФ.ХХХ - первая запись с равным или больше ключом
//    пока ДБФ.ВКонце()=0 цикл
//      ДБФ.ХХХ - остальные записи с равным или больше ключом

КонецЕсли;
12 Mikeware
 
23.05.16
11:29
(10) Ты не "все" достаешь,  а по очереди.
после НайтиПоКлючу - у тебя либо конец файла, либо выборка записей
13 Mikeware
 
23.05.16
11:30
(11) после установки индекса вроде надо передернуть позицию.
сделай, например, .Первая()
14 BalBess
 
23.05.16
11:53
(12) все-равно не получается ((

ДБФ.ТекущийИндекс("IDXPRICE");
ДБФ.Первая();
Цена = 100;    
ДБФ.КЛЮЧ.PRICE=Цена;
    
Если ДБФ.НайтиПоКлючу(0) > 0 тогда
//    ДБФ.ХХХ - первая запись с равным или больше ключом
    пока ДБФ.ВКонце()=0 цикл
    //      ДБФ.ХХХ - остальные записи с равным или больше ключом
            
        Сообщить(ДБФ.NAME);            

        ДБФ.Следующая();
    КонецЦикла;

КонецЕсли;

Выходят все поля, а не только с ценой 100
15 BalBess
 
23.05.16
11:58
Вернее выходят поля у которых цена БОЛЬШЕ или равна 100
и работает горазззздо дольше, 2100мс
16 Mikeware
 
23.05.16
11:59
(14) ДБФ.НайтиПоКлючу(0)- ищет точное соответсвие
17 BalBess
 
23.05.16
12:10
(16) ну да! сам удивляюсь
пробовал ДБФ.НайтиПоКлючу("="), то-же самое
и самое главное: работает гораздо дольше
18 BalBess
 
23.05.16
12:25
набросал тест, может кто у себя проверить?

Процедура Сформировать()
    ДБФ = СоздатьОбъект("XBase");

    ДБФ.ДобавитьПоле("NAME", 2, 100, 0);
    ДБФ.ДобавитьПоле("PRICE", 1, 8, 2);
    
    //ДобавитьИндекс(<Название>, <Выражение>, <Уникальность>, <Убывание>, <Фильтр>)
    ДБФ.ДобавитьИндекс("IDXPRICE", "PRICE", 0, 0, "");

    ДБФ.СоздатьФайл("c:\temp\goods.dbf", "c:\temp\goods.cdx");
    ДБФ.ОчиститьФайл();

ДБФ.Добавить();
ДБФ.NAME = "Булка хлеба";
ДБФ.PRICE = 20;
ДБФ.Записать();    


ДБФ.Добавить();
ДБФ.NAME = "Два кусочека колбаски";
ДБФ.PRICE = 100;
ДБФ.Записать();    

ДБФ.Добавить();
ДБФ.NAME = "Коньяк Арарат";
ДБФ.PRICE = 1000;
ДБФ.Записать();    
    
ДБФ.Переиндексировать();



    ДБФ.ТекущийИндекс("IDXPRICE");
    ДБФ.Первая();
    
    Цена = 100;
    
    ДБФ.КЛЮЧ.PRICE=Цена;
    
    Если ДБФ.НайтиПоКлючу("=") > 0 тогда
//        ДБФ.ХХХ - первая запись с равным или больше ключом
        пока ДБФ.ВКонце()=0 цикл
//      ДБФ.ХХХ - остальные записи с равным или больше ключом
            
            Сообщить("" + ДБФ.NAME);

            ДБФ.Следующая();
        КонецЦикла;

    КонецЕсли;

КонецПроцедуры
19 BalBess
 
23.05.16
12:37
добавил простой перебор
даже на таком простом примере видно что перебор работает быстрее. У меня 4мс, против 1мс

//*******************************************
Процедура Сформировать()
    ДБФ = СоздатьОбъект("XBase");

    ДБФ.ДобавитьПоле("NAME", 2, 100, 0);
    ДБФ.ДобавитьПоле("PRICE", 1, 8, 2);
    
    //ДобавитьИндекс(<Название>, <Выражение>, <Уникальность>, <Убывание>, <Фильтр>)
    ДБФ.ДобавитьИндекс("IDXPRICE", "PRICE", 0, 0, "");

    ДБФ.СоздатьФайл("c:\temp\goods.dbf", "c:\temp\goods.cdx");
    ДБФ.ОчиститьФайл();

ДБФ.Добавить();
ДБФ.NAME = "Булка хлеба";
ДБФ.PRICE = 20;
ДБФ.Записать();    


ДБФ.Добавить();
ДБФ.NAME = "Два кусочека колбаски";
ДБФ.PRICE = 100;
ДБФ.Записать();    

ДБФ.Добавить();
ДБФ.NAME = "Коньяк Арарат";
ДБФ.PRICE = 1000;
ДБФ.Записать();    
    
ДБФ.Переиндексировать();


    Начало = _GetPerformanceCounter(); //зафиксируем начало процесса...


    ДБФ.ТекущийИндекс("IDXPRICE");
//    ДБФ.Первая();
    
    Цена = 100;
    
    ДБФ.КЛЮЧ.PRICE=Цена;
    
    Если ДБФ.НайтиПоКлючу("=") > 0 тогда
//        ДБФ.ХХХ - первая запись с равным или больше ключом
        пока ДБФ.ВКонце()=0 цикл
//      ДБФ.ХХХ - остальные записи с равным или больше ключом
            
            Сообщить("" + ДБФ.NAME);

            ДБФ.Следующая();
        КонецЦикла;

    КонецЕсли;
    
    
    Конец = _GetPerformanceCounter(); //зафиксируем окончание процесса...
    Сообщить("" + (Конец - Начало)); //вычислим время выполнения цикла в секундах.
    
    // простой перебор
    Начало = _GetPerformanceCounter(); //зафиксируем начало процесса...
    
    ДБФ.Первая();

    Пока 1 = 1 Цикл
        Если ДБФ.Следующая() = 0 Тогда
            Прервать;
        КонецЕсли;

        Если ДБФ.PRICE <> Цена Тогда
            Продолжить;            
        КонецЕсли;
        Сообщить("" + ДБФ.NAME);
        
    КонецЦикла;

    Конец = _GetPerformanceCounter(); //зафиксируем окончание процесса...
    Сообщить("" + (Конец - Начало)); //вычислим время выполнения цикла в секундах.
    

КонецПроцедуры
20 Mikeware
 
23.05.16
12:49
(19) естественно, тупой перебор быстрее. а теперь перебери пару миллионов записей...
21 BalBess
 
23.05.16
12:55
(20) ну фиг его знает, я проверял на 40тыщ записей
поиск по ключу 2100мс, а перебор 100мс
на 3 записях я еще поверю, установка ключей, поиск и т.д.
но не на 40тыщ - же
И самое ГЛАВНОЕ: не находит точное соответствие ключу!
22 Mikeware
 
23.05.16
13:14
(21) значит, что-то с руками.
у меня работало
23 BalBess
 
23.05.16
13:45
(22) мож и руки конечно, но код-же я привел..
мож там какой команды не хватает
или может НайтиПоКлючу() для поиска одной записи..

есть у кого мысли, по этому поводу )
24 Ёпрст
 
23.05.16
13:46
(0) на вот, наслаждайся
https://cloud.mail.ru/public/ED6T/M7DrVqnxT

Тупо запрос к файлику и там что угодно - группировки, фильтры и т.д
25 NorthWind
 
23.05.16
13:49
(0) если стандартными средствами, то по-моему, там только нафигационный метод. Т.е. найти первую запись и дальше пока условиям поиска удовлетворяет.
Ну или если так неохота, тогда можно попробовать открыть средствами ADO (провайдер MS Jet) и дальше обычный SQL. Я, правда, так не пробовал, но не вижу, почему бы могло не получиться.
26 NorthWind
 
23.05.16
13:52
вот здесь описана строка коннекта ADO+MS Jet 4.0 для файлов dbf:
https://support.microsoft.com/ru-ru/kb/326548#bookmark-3
27 BalBess
 
23.05.16
14:00
(24) (25) (26) не знаю, нужно-ли настолько все усложнять
и будет-ли это работать быстрее простого перебора
это програмка будет стоять на старых машинах с WinXP
в принципе там все работает, кроме поиска по цене "реал-тайм",
сейчас работает по принципу, набрал цену, нажал поиск
а я хочу набрал цифру 1, вывелись товары с ценой 1р, нажал 0, вывелись товары с ценой 10р, и т.д.
28 Mikeware
 
23.05.16
14:06
(27) поклади куданить файлик, посмотрю...
29 Ёпрст
 
23.05.16
15:11
(27) будет работать быстрее, если будет задействован подходящий индекс
30 Ёпрст
 
23.05.16
15:12
ну а просто уссловие, для такого маленького файла, это милисекунды
31 Mikeware
 
23.05.16
15:27
(30) ну 40 тыщ записей - всяко быстрее, чем перебор должно быть...
32 Djelf
 
23.05.16
22:32
dbf... dbf...
1sqlite, 770к записей (загруженная из xml база алкогольных лицензий), отбор 618 записей по индексу инн - 160мс на холодную базу (полный перезапуск компа) и 2мс на горячую
33 BalBess
 
24.05.16
09:35
Сорри за задержку..
(28) http://файлообменник.рф/s5ueadz6bx1w.html
попробуйте отсюда скачать, если не получиться пишите
(32) я понимаю что вариантов реализации множество, в 1с77 встроенна поддержка dbf, мне нужно чтобы работало из коробки. Програмка простенькая, не хочу ее наворачивать 1sqlite, ADO+MS Jet 4.0 и иже с ними.
34 BalBess
 
24.05.16
09:41
(28) либо вот
https://cloud.mail.ru/public/JQp4/K23EjSE8Y
это файлик без индексов, там продукты, еще есть такой-же хозтовары, но я думаю хватит одного для тестов
35 BalBess
 
24.05.16
11:39
Кажется разобрался.
В общем метод НайтиПоКлючу() - видимо сортирует таблицу по этому ключу, и устанавливает указатель на первую запись
Если в цикле вставить проверку на этот ключ, то все начинает работать на порядок быстрее.
Без проверки время было 2000мс, с проверкой 5-10мс. Напомню прямым перебором у меня было 100мс

ДБФ.ТекущийИндекс("IDXPRICE");
ДБФ.КЛЮЧ.PRICE=Цена;
    
Если ДБФ.НайтиПоКлючу("=") > 0 тогда
//    ДБФ.ХХХ - первая запись с равным или больше ключом
    пока ДБФ_товары.ВКонце()=0 цикл
//      ДБФ.ХХХ - остальные записи с равным или больше ключом
           
        Если ДБФ.PRICE > Цена Тогда
            Прервать;    
        КонецЕсли;
        
        Сообщить(ДБФ.NAME);

        ДБФ.Следующая();
    КонецЦикла;
КонецЕсли;
36 BalBess
 
24.05.16
11:41
Всем большое спасибо! как всегда форум выручил))
37 Mikeware
 
24.05.16
12:01
(35) он не сортирует по ключу - он строит индекс. Ну, типа сортировки, да...
но вроде при поиске по ключу по равенству - должен выбирать только равные, и заканчивать выборку по еоф.
ДБФ.НайтиПоКлючу("=") - не знаю
попробуй как в СП, ДБФ.НайтиПоКлючу(0)
38 BalBess
 
24.05.16
12:43
(37) я пробовал и так и так, эффект тот-же
я думаю так, он же не может удалить записи из таблицы (те которые не проходят по условию). Просто он упорядочивает их (по ключу), и ставит указатель на первый.
Т.е. в таблице остаются ВСЕ записи, только отсортированные, остается выбрать нужные ))
Если взять все записи после НайтиПоКлючу(0), то видно что они отсортированные именно по цене становятся
39 Bigbro
 
24.05.16
12:58
у меня был такой же результат как в (35) прерывать приходилось по условию.
40 Mikeware
 
24.05.16
13:13
ну, значит я все уже позабыл нафик...