27.11.2007, 23:24 | #1 |
Участник
|
Всем привет.
Хотелось бы обсудить преимущества FINDSET над FIND('-'). Уточняю, я рассматриваю FINDSET без параметров. На сколько я понимаю, FINDSET не создает курсор, что не блокирует набор данных, НО если набор данных превысит максимальный размер записей для кеширования, то курсор все таки будет создан. Т.е. FINDSET дает выигрышь в производительности только до 500 (по умолчанию) записей. Поправьте меня если я не прав и хотелось бы услышать другие мнения. |
|
19.08.2009, 17:11 | #2 |
Участник
|
Мне вот показалось, что FINDSET берет информацию блоками по 500 записей по-умолчанию.
|
|
20.08.2009, 12:24 | #3 |
Участник
|
Цитата:
Сообщение от ekya
Всем привет.
Хотелось бы обсудить преимущества FINDSET над FIND('-'). Уточняю, я рассматриваю FINDSET без параметров. На сколько я понимаю, FINDSET не создает курсор, что не блокирует набор данных, НО если набор данных превысит максимальный размер записей для кеширования, то курсор все таки будет создан. Т.е. FINDSET дает выигрышь в производительности только до 500 (по умолчанию) записей. Поправьте меня если я не прав и хотелось бы услышать другие мнения. |
|
13.06.2013, 07:38 | #4 |
Участник
|
В справке не нашел информации о параметрах по умолчанию для FINDSET, не подскажете, с какими она вызывается? Экспериментировать неохото)
|
|
13.06.2013, 10:47 | #5 |
Участник
|
Цитата:
Цитата:
FINDSET (Record)
Use this function to find a set of records in a table based on the current key and filter. The records can only be retrieved in ascending order. Ok := Record.FINDSET([ForUpdate][, UpdateKey]) Ok Data type: boolean If you omit this optional return value, a run-time error occurs if the system cannot find a record. If you include a return value, the system assumes you will handle any errors. Ok can have these values: If Ok is... It means the record set was... TRUE Found FALSE Not found Record Data type: record If the record was... Then... Found The system returns the record in Record and sets any FlowField in the record to zero. You must update them using CALCFIELDS. Not found A run-time error occurs, if you omitted the return value Ok. ForUpdate Data type: boolean Set this to FALSE if you don't intend to modify any records in the set. Set this to TRUE if you want to modify some records in the set. If you set this parameter to TRUE, a LOCKTABLE is immediately performed on the table before the records are read. UpdateKey Data type: boolean This only applies if ForUpdate is set to TRUE. If you are going to modify any field value within the current key, set this parameter to TRUE. Comments You should only use this function when you explicitly want to loop through a recordset. You should ONLY use this function in combination with REPEAT .. UNTIL. Furthermore, FINDSET only supports descending loops. If you want to loop from the bottom up, you should use FIND(‘+’). The general rules for using FINDSET are: • FINDSET(FALSE,FALSE)- read-only. This uses no server cursors and the record set is read with a single server call. • FINDSET(TRUE,FALSE)- is used to update non-key fields. This uses a cursor with a fetch buffer similar to FIND(‘-’). • FINDSET(TRUE,TRUE)- is used to update key fields. Note This function is designed to optimize finding and updating sets. If you set any or both of the parameters to FALSE, you can still modify the records in the set but these updates will not be performed optimally. Example The following C/AL code examples show how to use the FINDSET function: Example 1 // Looping through a set without updating it. SalesLine.SETFILTER("Purch. Order Line No.",'<>0'); IF SalesLine.FINDSET THEN BEGIN REPEAT CopyLine(SalesLine); UNTIL SalesLine.NEXT = 0; END; Example 2 // Looping through a set and updating a field that is not within the current key. SalesLine.SETRANGE("Document Type",DocumentType); SalesLine.SETRANGE("Document No.",DocumentNo); IF SalesLine.FINDSET(TRUE, FALSE) THEN BEGIN REPEAT SalesLine."Location Code" := GetNewLocation(SalesLine); SalesLine.MODIFY; UNTIL SalesLine.NEXT = 0; END; Example 3 // Looping through a set and updating a field that is within the current key. SalesShptLine.SETRANGE("Order No.",SalesLine."Document No."); SalesShptLine.SETRANGE("Order Line No.",SalesLine."Line No."); SalesShptLine.SETCURRENTKEY("Order No.","Order Line No."); IF SalesShptLine.FINDSET(TRUE, TRUE) THEN BEGIN REPEAT SalesShptLine."Order Line No." := SalesShptLine."Order Line No." + 10000; SalesShptLine.MODIFY; UNTIL SalesShptLine.NEXT = 0; END; |
|
13.06.2013, 11:04 | #6 |
Участник
|
Господа не все так однозначно))) Вот например, выдержка из хелпа по 2009 наву (выделенное жирным заставляет меня задумываться о возвращении использования FIND('-'), но все надо тестировать, а руки не доходят):
The FINDSET operation optimizes reading records from SQL Server by establishing a stream of records between Microsoft Dynamics NAV and SQL Server. While the stream is open, no other activity occurs between Microsoft Dynamics NAV and SQL Server. Before the records are read, Microsoft Dynamics NAV has no information about how many records are available to read. However, Microsoft Dynamics NAV must allocate enough memory to accommodate all records that it will read for the FINDSET operation. The stream does not allow it to read records in groups. Microsoft Dynamics NAV allocates memory for a preset number of records and then begins reading the records. You can change the value of this preset number by changing the Record Set value in the New Database or Alter Database window. For more information, see the topic "Entering Information in the New Database - Advanced Tab" in the Microsoft Dynamics NAV Application Help. Note In Microsoft Dynamics NAV 2009, the default value is 50. In Microsoft Dynamics NAV 5.0, when the FINDSET operation was introduced, the default value was 500. If the number of records that is read falls within this range, then all records are read with optimized performance. If there are more records to read than the preset number, then Microsoft Dynamics NAV must establish new commands to SQL Server to continue reading records. Microsoft Dynamics NAV reads all records successfully, but the additional commands are expensive for SQL Server to execute. The FIND('-') operation is more efficient than the FINDSET operation when there are more records to read than the preset number. Note If Microsoft Dynamics NAV detects a pattern in which FINDSET would be a better choice than FIND, then it converts the FIND operation to a FINDSET operation. |
|
18.06.2013, 12:17 | #7 |
Участник
|
__________________
--------------------------------------------------------------------------------------------- "Собрать стадо из баранов легко, трудно собрать стадо из кошек" Профессор Сергей Капица |
|
24.06.2013, 10:57 | #8 |
Участник
|
Спасибо Kadawrik за цитирование справки из своего навика, у меня примерно такая же, но т.к. есть отличия, мне пришлось перечитать ее еще раз... Вопрос актуален, с какими параметрами по умолчания вызывается FINDSET? Мне не по глазам или просто с первого раза был непонятен мой вопрос?) Я так и не нашел этого...
|
|
24.06.2013, 17:00 | #9 |
Участник
|
|
|
01.07.2013, 01:00 | #10 |
Участник
|
|
|
19.06.2014, 10:43 | #11 |
Участник
|
В развитии своей проблемы забрел в эту тему)) Собственно профайлер SQL показал:
1. При FINDSET в SQL при обходе в цикле происходит следующее(запрос целиком не привожу - ясно будет и так, в конце каждого запроса имеется WHERE по наложенным на таблицу фильтрам): SELECT TOP 51 ......... - при первом подходе и SELECT TOP 1 ........ до конца выборки, если в ней больше выбранных за первый подход записей 2. При FIND('-') выявлено: SELECT (*) ....... Итог: Если в таблице после наложения фильтров остается 1-150 записей - FINDSET работает быстрее FIND('-'), причем увеличение записей приводит к их уравниванию. Примерно одинаково отрабатывают оба варианта в диапазоне 200-400 записей Если выборка составляет более 1000 записей FIND('-') выигрывает у FINDSET уже довольно серьезно (на 36000 записей: FINDSET показал результат 258000мс, FIND('-') - 150000мс. Был организован простой проход в цикле по записям выборки с записью в лог разницы во времени между итерациями цикла, таблица "Customer Ledger Entry"). Пост всего лишь описание найденного узкого места по FIND vs FINDSET - необходимо представлять какое количество будет при выборке, и в зависимости от этого плясать...
__________________
Как только вы проиграете, все ваши прошлые победы забудут. |
|
14.07.2014, 13:34 | #12 |
Участник
|
Уже что-то не так в логике, раз приходится переперать сотни записей.
Есть ещё косяк интересный, если рекурсивно делать FINDSET к одной и той же таблице(вложенно). FINDSET вроде как кеширует набор, но при вложенности кеш слетает, и летят кривые запросы к базе. Жуть как торомозит. |
|
30.09.2015, 12:36 | #13 |
Участник
|
Нашёл сегодня повод поднять эту старую тему.
Я тут случайно обнаружил, что из NAV2013 и NAV2015 исчез параметр отвечающий за размер кэша для FINDSET. Кроме того, из хелпа пропали описания различий между FIND и FINDSET. Сами же описания данных функций стали до безобразия скудны. Всё это заставляет задуматься, а как теперь всё это работает? И где про это можно почитать? |
|