Имя: Пароль:
1C
1C 7.7
v7: 1sqlite vs vfpoledb по сети
0 Дык ё
 
08.12.12
14:02
господа! помогите начинающему dbfнику

есть одинаковые по структуре запросы на vfpoledb и 1sqlite
время выполнения локально: 350мс vfp, 17мс sqlite. тут все хорошо
время выполнения по сети: ~7сек vfp, ~86сек sqlite. опаньки

что я не учел? мне нужно по сети, и хочется 1sqlite
http://dev.mista.ru/topic.php?id=554041 читал. судя по времени выполнения vfpoleb, дело не в кэшировании
нужна помощь зала
1 kiruha
 
08.12.12
14:13
Индексы в vfpoledb  надо указывать вручную,
тогда время улучшится на порядок
http://www.1cpp.ru/forum/YaBB.pl?num=1184317705

в 1sqlite  они подбираются автоматически
2 Torquader
 
08.12.12
14:13
Начнём с того, что SLQ-lite работает с dbf-файлами, то есть открывает просто файлы. При работе по сети, если работает только один клиент, система включает кеширование, так как уверена, что данные в самом файле не будут отличаться от кеша. Если работает несколько клиентов, то включается механизм очистки кеша - он не умеет отслеживать блоки в файлах, а только файлы целиком, то есть если один сеанс что-то записал в файл, то другой запрашивает этот файл снова с сервера (UDP-датаграммы туда и обратно) и получается, что за каждой строкой (а dbf-файлы обрабатываются построчно) система лазит на сервер.
И есть подозрение, что решения у данной проблемы нет, так как мы не можем лезть внутрь dll.
3 Torquader
 
08.12.12
14:15
Кстати, vfp-драйвер работает с другим типом индексов - то есть напрямую заглянуть в 1С на запись не получится, а в случае чтения будет прямой выбор.
vfp- хорошо работает, если ему давать свои файлы - тогда работает и блокировка на время исполнения и пакеты запросов, но к 1С это относится также, как сторонний sql-сервер через OleDb.
4 kiruha
 
08.12.12
14:20
(3)
dbf файл он и в Африке dbf Как и CDX
P.S>
тут полно людей которые работали на практике и на живых базах через сабж (0)
5 Aleksey
 
08.12.12
14:21
(4) Не скажи, как раз в CDX и проблема ограничивающая прямую запись в dbf файл
6 Дык ё
 
08.12.12
14:36
(1) мне пока не надо лучше на порядок. достаточно будет быстрее, чем vfpoledb

(2) а почему vfpoledb страдает от этого на порядок меньше? основной вопрос в этом
7 Torquader
 
08.12.12
14:40
(6) Если он индексы не читает, то он просто запрашивает один dbf-файл кусками, а в случае работы с индексами будет несколько запросов cdx-файлов, причём со смещением.
Есть подозрение, что при простом чтении dbf-файла читается не строка, а сразу блок строк (нужно смотреть как FoxPro устроен).
8 Холст
 
08.12.12
14:41
9 Torquader
 
08.12.12
14:47
(8) В этом случае, файлы не открываются по сети, но за каждым файлом всё равно идёт обращение на сервер - единственное, что ускоряет процесс - отсутствие ожидания снятия блокировок со стороны других клиентов, так как можно просто подождать, пока файл освободиться, а не делать попытки его заблокировать, как делает это 1С.
10 orefkov
 
08.12.12
17:44
Запрос надо смотреть.
11 Дык ё
 
08.12.12
18:28
(10) в понедельник, запрос на работе остался. но локально то он в 20 раз быстрее :о
12 Дык ё
 
10.12.12
10:09
(10) в попытках переезда проверялось несколько запросов, и во всех случаях наблюдалась проблема из (0). запрос, о котором шла речь в (0) после отладки:

SELECT ltrim(nom.CODE) As Артикул
   , rtrim(nom.DESCR) As Наименование
   , fOST.НачОст
   , fOST.Приход
   , fOST.Расход
   , fOST.КонОст
   , fOST.Details AS Детализация
   , (2 - CASE WHEN fOST.НачОст = 0 THEN 1 ELSE 0 END - CASE WHEN fOST.Details = '' THEN 1 ELSE 0 END) AS флБылиДвижения
FROM(
   SELECT Товар
       , Doc As Details, DateTime
       , Sum(НачОст) As НачОст
       , Sum(Приход) As Приход
       , Sum(Расход) As Расход
       , Sum(КонОст) As КонОст
   FROM (
       SELECT itog.Товар As Товар
           , '             ' As Doc, '              ' As DateTime
           , itog.Количество As НачОст
           , 0 As Приход
           , 0 As Расход
           , itog.Количество As КонОст
       FROM РегистрИтоги_ОстаткиТоваров AS itog
       WHERE itog.PERIOD = '20121101'
           
       UNION ALL
       SELECT dv.Товар As Товар
           
           , CASE WHEN jrn.date >= '20121207' THEN jrn.iddocdef || jrn.iddoc ELSE '             ' END AS Doc
           , CASE WHEN jrn.date >= '20121207' THEN jrn.Date || jrn.Time ELSE '              ' END As DateTime
           , CASE WHEN jrn.date <  '20121207' THEN (1-2*dv.debkred)*dv.Количество ELSE 0 END As НачОст
           , CASE WHEN (jrn.date >= '20121207') AND (dv.debkred = 0) THEN dv.Количество ELSE 0 END As Приход
           , CASE WHEN (jrn.date >= '20121207') AND (dv.debkred = 1) THEN dv.Количество ELSE 0 END As Расход
           , (1-2*dv.debkred)*dv.Количество As КонОст
       FROM Журнал As jrn
           INNER JOIN Регистр_ОстаткиТоваров As dv ON jrn.iddoc = dv.iddoc
       WHERE jrn.idx_DATE_TIME_IDDOC BETWEEN '20121201' AND '20121207Я'
           
       ) As OST
   GROUP BY Товар, Doc, DateTime
   ) As fOST
   LEFT JOIN Справочник_Номенклатура As nom ON nom.ID = fOST.Товар
   LEFT JOIN Справочник_Номенклатура As par1 ON par1.ID = nom.PARENTID
   LEFT JOIN Справочник_Номенклатура As par2 ON par2.ID = par1.PARENTID
   LEFT JOIN Справочник_Номенклатура As par3 ON par3.ID = par2.PARENTID
   LEFT JOIN Справочник_Номенклатура As par4 ON par4.ID = par3.PARENTID
   LEFT JOIN Справочник_Номенклатура As par5 ON par5.ID = par4.PARENTID
   LEFT JOIN Справочник_Номенклатура As par6 ON par6.ID = par5.PARENTID
   LEFT JOIN Справочник_Номенклатура As par7 ON par7.ID = par6.PARENTID
   LEFT JOIN Справочник_Номенклатура As par8 ON par8.ID = par7.PARENTID

ORDER BY coalesce(par6.DESCR, par5.DESCR, par4.DESCR, par3.DESCR, par2.DESCR, par1.DESCR, '')
   , coalesce(par5.DESCR, par4.DESCR, par3.DESCR, par2.DESCR, par1.DESCR, '')
   , coalesce(par4.DESCR, par3.DESCR, par2.DESCR, par1.DESCR, '')
   , coalesce(par3.DESCR, par2.DESCR, par1.DESCR, '')
   , coalesce(par2.DESCR, par1.DESCR, '')
   , coalesce(par1.DESCR, '')
   , nom.DESCR, DateTime
13 Ёпрст
 
гуру
10.12.12
10:15
(12) блин.. и не лень тебе было вот так писать:

from Регистр_ОстаткиТоваров
JOIN Справочник_Номенклатура

еще и перед запросом сами таблички эти задавал поди, да ?
14 Ёпрст
 
гуру
10.12.12
10:17
да и проще флаг в регистр воткнуть, чем такое извращение с журналом в тексте запроса..
ну и '     ' в качестве "пустого" документа..оригинально.
15 Ёпрст
 
гуру
10.12.12
10:24
и потом..
вот тут ты с '' сравниваешь
when fOST.Details = ''

а унутри пихаешь '      '
16 Дык ё
 
10.12.12
10:39
(13) зачем создавать? 1sqlite автоматом родные таблицы подключает ;-)

(14) я же говорю, переписываю запрос на vfpoledb (который писали до меня). задача на данном этапе - не красивый запрос, а сравнимая производительность
17 Ёпрст
 
гуру
10.12.12
12:42
(16) а чего с производительностью ?
фокс при попадании в индекс всегда быстрее будет на таком запросе.
18 Ёпрст
 
гуру
10.12.12
12:43
и не важно где - в сетки или локально
19 Дык ё
 
10.12.12
13:04
(17) мать-перемать! читай (0). локально sqlite быстрее в 20 раз, по сети на тех же запросах медленнее в 10 раз. вопрос - почему?
20 kiruha
 
10.12.12
13:14
(19)
Потому, что нет отборов тащишь по сетке Х Мб
например здесь

FROM РегистрИтоги_ОстаткиТоваров AS itog
       WHERE itog.PERIOD = '20121101'

не понимаю зачем тогда нужны прямые - тупо выгружаешь регистр (ВыгрузитьИтоги) и дальше работаешь с ТЗ - скорость будет та же
21 Ёпрст
 
гуру
10.12.12
13:15
(19) не задействован индекс в фоксе
22 Дык ё
 
10.12.12
13:22
(20) почему нет? 1sqlite в этом месте попадает в индекс PROP. и таки да, мне нужны остатки по всем товарам

(21) ты не поверишь... :-)
23 Ёпрст
 
гуру
10.12.12
13:23
(22) ну дык покажи запрос на фоксе..
24 Ёпрст
 
гуру
10.12.12
13:24
а скульлайт по сети.. всегда тормоз, Орефков что-то объяснял по этому аоводу, не помню ужо.
25 Ёпрст
 
гуру
10.12.12
13:25
а фокс при попадании в индекс всегда будет быстрее на этом запросе (и локально в том числе)
26 Дык ё
 
10.12.12
13:25
(24) вспомни плиз, ты же все записываешь
27 Дык ё
 
10.12.12
13:32
(23) SELECT
   iif(IsNull(par1.ID),1,iif(IsNull(par2.ID),2,iif(IsNull(par3.ID),3,iif(IsNull(par4.ID),4,iif(IsNull(par5.ID),5,iif(IsNull(par6.ID),6,7)))))) As _level,
   iif(not IsNull(par6.DESCR),par6.DESCR,iif(not IsNull(par5.DESCR),par5.DESCR,iif(not IsNull(par4.DESCR),par4.DESCR,iif(not IsNull(par3.DESCR),par3.DESCR,iif(not IsNull(par2.DESCR),par2.DESCR,iif(not IsNull(par1.DESCR),par1.DESCR,cast('' as char(80)))))))) As _exp1,
   iif(not IsNull(par5.DESCR),par5.DESCR,iif(not IsNull(par4.DESCR),par4.DESCR,iif(not IsNull(par3.DESCR),par3.DESCR,iif(not IsNull(par2.DESCR),par2.DESCR,iif(not IsNull(par1.DESCR),par1.DESCR,cast('' as char(80))))))) As _exp2,
   iif(not IsNull(par4.DESCR),par4.DESCR,iif(not IsNull(par3.DESCR),par3.DESCR,iif(not IsNull(par2.DESCR),par2.DESCR,iif(not IsNull(par1.DESCR),par1.DESCR,cast('' as char(80)))))) As _exp3,
   iif(not IsNull(par3.DESCR),par3.DESCR,iif(not IsNull(par2.DESCR),par2.DESCR,iif(not IsNull(par1.DESCR),par1.DESCR,cast('' as char(80))))) As _exp4,
   iif(not IsNull(par2.DESCR),par2.DESCR,iif(not IsNull(par1.DESCR),par1.DESCR,cast('' as char(80)))) As _exp5,
   iif(not IsNull(par1.DESCR),par1.DESCR,cast('' as char(80))) As _exp6,
   ltrim(nom.CODE) As TvrCODE,
   rtrim(nom.DESCR) As TvrDESCR,
   fOST.*
FROM(
   SELECT
       Товар,  Doc As Details, DateTime,
       Cast(Sum(НачОст) as Char(19)) As НачОст,
       Cast(Sum(Приход) as Char(19)) As Приход,
       Cast(Sum(Расход) as Char(19)) As Расход,
       Cast(Sum(КонОст) as Char(19)) As КонОст
   FROM(
       SELECT
           itog.sp5600 As Товар,
           '             ' As Doc, '              ' As DateTime,
           itog.sp5602 As НачОст,
           0 As Приход,
           0 As Расход,
           itog.sp5602 As КонОст
       FROM rg5599 As itog
       WHERE DTOS(itog.PERIOD) + itog.sp5601 like DTOS(Date(2012,11,1)) + '_______________'
       
       UNION ALL
       SELECT
           dv.sp5600 As Товар,
           iif(jrn.date >= Date(2012,12,10), jrn.iddocdef + jrn.iddoc, '             '), iif(jrn.date >= Date(2012,12,10), Dtos(jrn.Date) + jrn.Time, '              ') As DateTime,
           Cast(iif(jrn.date <   Date(2012,12,10), (1-2*dv.debkred)*dv.sp5602, 0) as int) As НачОст,
           Cast(iif((jrn.date >= Date(2012,12,10)) AND (dv.debkred = 0), dv.sp5602, 0) as int) As Приход,
           Cast(iif((jrn.date >= Date(2012,12,10)) AND (dv.debkred = 1), dv.sp5602, 0) as int) As Расход,
           Cast((1-2*dv.debkred)*dv.sp5602 as int) As КонОст
       FROM ra5599 As dv
       INNER JOIN 1SJOURN As jrn ON jrn.iddoc = dv.iddoc
       WHERE DTOS(jrn.date)+jrn.time+jrn.iddoc BETWEEN Dtos(Date(2012,12,1)) + '               ' AND  Dtos(Date(2012,12,10)) + 'ZZZZZZZZZZZZZZZ'
       
   ) As OST
   GROUP BY Товар, Doc, DateTime) As fOST
INNER JOIN sc51 As nom ON nom.ID = fOST.Товар
LEFT JOIN sc51 As par1 ON par1.ID = nom.PARENTID
LEFT JOIN sc51 As par2 ON par2.ID = par1.PARENTID
LEFT JOIN sc51 As par3 ON par3.ID = par2.PARENTID
LEFT JOIN sc51 As par4 ON par4.ID = par3.PARENTID
LEFT JOIN sc51 As par5 ON par5.ID = par4.PARENTID
LEFT JOIN sc51 As par6 ON par6.ID = par5.PARENTID
LEFT JOIN sc51 As par7 ON par7.ID = par6.PARENTID
LEFT JOIN sc51 As par8 ON par8.ID = par7.PARENTID

ORDER BY _exp1, _exp2, _exp3, _exp4, _exp5, _exp6, TvrDESCR, DateTime
28 kiruha
 
10.12.12
13:34
Года 3 назад скачал sqlite ( не 1sqlite ! можно свободно с http://www.sqlite.org ).

Открыл - смотрю на реализацию Left Join - условно говоря 20 ! строчек кода , простой перебор.
Малость офигел, вопросы снял
29 Ёпрст
 
гуру
10.12.12
13:47
(27) а чего галку быстрая обработка движений не ставишь у регистра, или хотя бы отбор движений у любого измерения, чтоб индекс был на табличке движений.. ?
30 Дык ё
 
10.12.12
13:52
(29) вот жеж :-) я понимаю, как это можно оптимизировать. я не понимаю, почему (19)?
31 Ёпрст
 
гуру
10.12.12
13:57
да не помню я..тем более, баз по сети нема, что б даже проверить
:)
32 Ёпрст
 
гуру
10.12.12
13:58
Орефкова пытай, это же его детище.
33 Ёпрст
 
гуру
10.12.12
14:00
Кстати, если воткнешь индекс на табличку движений, фокс обгонит скульлайт.. раз в 5.
Вот с соединением с журнальчиком, тоже не смог добиться скорости на фоксе.
34 orefkov
 
10.12.12
14:05
(28)
Не надо песен. 1sqlite пишу с 2008 года, т.е. 4 года назад начинал.
Где ты там в sqlite нашел реализацию лефт джойна в 20 строчек простым перебором - непонятно, наверное, ты плохо смотрел.
35 Ёпрст
 
гуру
10.12.12
14:09
(34) а на счет падения скорости при выполнении запроса скульлайта по сети ?
36 orefkov
 
10.12.12
14:25
(12)
Первое и главное - цеплять всю иерархию в запросе - очень тяжело. sqlite для каждого джойна таблицы товаров дергает движок 1С, не кэшируя результаты. Лучше выгрузить без иерархии, и накрутить ее в ИТЗ, там и отсортируется.
Раз быстрой обработки движений нет, воткни еще условие
Журнал.ОстаткиТоваровФр = 1
37 orefkov
 
10.12.12
14:27
(35)
А можно еще попробовать взвести запрос.ВыполнятьВТранзакции
Но однако, остальные будут обламываться на запись в регистр и журнал.
38 Ёпрст
 
гуру
10.12.12
14:28
(37) не.. я не об этом.
Почему такое падение производительности ?
39 Ёпрст
 
гуру
10.12.12
14:28
локально то шустро, а по сети - болт.
40 kiruha
 
10.12.12
14:29
(33)Можно малость быстрее
если известно, какие типы документов двигают регистр (как в 8)
то можно через индекс
IDDOCDEF,DATE,TIME,IDDOC


jrn.IDDOCDEF+DTOS(jrn.date)+jrn.time+jrn.iddoc BETWEEN $ВидДокумента.РасходнаяНакладная+Dtos(Date(2012,12,1)) + '               ' AND  $ВидДокумента.РасходнаяНакладная+Dtos(Date(2012,12,10)) + 'ZZZZZZZZZZZZZZZ'  

OR

jrn.IDDOCDEF+DTOS(jrn.date)+jrn.time+jrn.iddoc BETWEEN $ВидДокумента.ПриходнаяНакладная+Dtos(Date(2012,12,1)) + '               ' AND  $ВидДокумента.ПриходнаяНакладная+Dtos(Date(2012,12,10)) + 'ZZZZZZZZZZZZZZZ'

OR

jrn.IDDOCDEF+DTOS(jrn.date)+jrn.time+jrn.iddoc BETWEEN $ВидДокумента.Перемещение+Dtos(Date(2012,12,1)) + '               ' AND  $ВидДокумента.Перемещение+Dtos(Date(2012,12,10)) + 'ZZZZZZZZZZZZZZZ'

P.S> Если включена опция
ОлеДБКоманда.Выполнить("EXECSCRIPT('SET ANSI OFF')");
то запись выглядит изящнее
jrn.IDDOCDEF+DTOS(jrn.date)+jrn.time+jrn.iddoc =$ВидДокумента.РасходнаяНакладная+Dtos(Date(2012,12,1))
41 Ёпрст
 
гуру
10.12.12
14:33
(40) тогда уж.. лучше нужные виды в журнал запихать и потом через индекс IDJOURNAL,DATE,TIME,IDDOC  

:)

хотя проще, галку на регистр воткнуть
42 orefkov
 
10.12.12
14:45
(39)
Потому что на самом деле унутре для доступа к данным используется тот же родной 1Сный движок, sqlite только высокоуровневая обертка вокруг вызовов seek, scan и т.д.
Т.е. все те причины, которые вызывают тормоза 1С пр работе по сети, применимы и к 1sqlite.
43 Дык ё
 
10.12.12
15:08
(36) ВыполнятьВТранзакции - уже, ОстаткиТоваровФр - попробую, спасибо. а что кешируется в том кеше, который PRAGMA cache_size? его увеличение дало небольшой (~5%) профит

прикрутить ИТЗ - не вопрос. вопрос - переходить на 1sqlite или нет? при текущих сравнительных показателях производительности получается - нет. а хочется. ветка создана в надежде на то, что я чего-то не учитываю :-(
44 orefkov
 
10.12.12
15:49
(43)
В том кэше лежат данные самого sqlite, данные из виртуальных таблиц туда не попадают. Вернее, могут попасть уже на этапе сортировки. Так что скорее всего, большая часть расходов у тебя - передача по сети.
45 orefkov
 
10.12.12
15:50
Попробуй сравни время без кучи left join'ов и order by, будет ли выигрыш.
46 Кирпич
 
10.12.12
16:09
(0) если ты к vfp через ado подключаешься, то оно у тебя работает в режиме клиент-сервер, т.е. запрос на сервере выполняется. наверное по этому и быстрее.
47 Дык ё
 
10.12.12
16:55
(44) есть методические рекомендации по уменьшению этих расходов?

(45) есть выигрыш. без джойнов 1sqlite всего в 4 раза медленнее, чем vfpoledb с джойнами :-)
48 Ёпрст
 
гуру
10.12.12
16:59
(47) а индекс на табличку движений добавить и сравнить.. не ?
:)
49 kiruha
 
10.12.12
18:12
(47)
4 года назад
>> SqlLite не строит вспомогательные индексы при группировках и Order By и т.д.<<
Т.е. сохранив во временную и проиндексировав на больших табличках можно добиться ускорения
50 orefkov
 
10.12.12
21:15
(49)
Как раз таки строит.
Сортировка при отсутствии индекса делается укладывались в неявную врем.таблицу с индексом по сортируемым полям и с дальнейшим проходом по ней по этому индексу. Для группировки - во время такого прохода наворачиваются итоги.
51 orefkov
 
10.12.12
21:15
(47)
Расход памяти сравнивал?
52 Дык ё
 
13.12.12
09:50
(51) нет, а зачем?

похоже, 1sqlite совсем не умеет в кеширование. добавление в запрос таблицы, котора там уже есть, заметно увеличивает время выполнения. на vfpoledb этого не наблюдается.

отдельно доставляет scan table в планах выполнения на таблицах 1с, хотя на родных таблицах в аналогичных запросах выполняется ожидаемый search table. но тут не могу сказать, на сколько это плохо - не знаю, как оно там устроено внутри
53 Ёпрст
 
гуру
13.12.12
09:57
(52) дык, можешь же явно индекс указать в тексте, тоже скан ?
54 Ёпрст
 
гуру
13.12.12
09:58
а ё.. вижу, и так указан у тебя в запросе .idx_.....
Проблемы невозможно решaть нa том же уровне компетентности, нa котором они возникaют. Альберт Эйнштейн