Nota techniczna
z dn. 16-05-2025
Wytyczne dotyczące widoków list i sekcji typu lista
Wpływ na wydajność wyświetlania listy, autonomicznej lub w sekcji formularza, ma nie tylko ilość danych, ale również konstrukcja zapytania zwracającego dane wyświetlane na liście. Większość zapytań SQL definiowanych przez konsultantów w AdminSPA jest podczas wykonywania opakowywana w dodatkowe instrukcje. Aby zobaczyć, jak faktycznie wygląda zapytanie wysyłane do bazy można skorzystać z MiniProfilera i wyświetlić podgląd żądania Grid/GetGridPartialContent.
Zapytanie wykonywane w celu wyświetlenia strony rekordów widoku listy z kontrolą uprawnień ACL, skonfigurowanym filtrem i ustawionym sortowaniem wygląda następująco:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
SELECT (
SELECT COUNT(*) FROM (
SELECT * FROM (
SELECT * FROM (
SELECT * FROM (
SELECT * FROM [rklRjs_View]('1') -- zapytanie źródłowe listy
) AS _FilterGridQueryTable_ WHERE ([CREATEDATE] <= '2025-05-14 15:16') -- filtr listy
) AS [GRIDContext] WHERE [GRIDContext].[ACLId] IN ( -- kontrola ACL
SELECT [ACLId]
FROM [core].[GetAclIds]('18ef4e5e-11ee-41cd-5a9d-08d8da52c48b', 1, 'InstanceWithStatus'))
) AS _FilterQueryTable_
) AS _CountResult_
) AS [TotalRecords],
0 AS [Offset],
100 AS [Take],
( SELECT TOP(100) * FROM (
SELECT * FROM (
SELECT * FROM (
SELECT * FROM (
SELECT * FROM [rklRjs_View]('1')
) AS _FilterGridQueryTable_ WHERE ([CREATEDATE] <= '2025-05-14 15:16')
) AS [GRIDContext] WHERE [GRIDContext].[ACLId] IN (
SELECT [ACLId]
FROM [core].[GetAclIds]('18ef4e5e-11ee-41cd-5a9d-08d8da52c48b', 1, 'InstanceWithStatus'))
) AS _FilterQueryTable_ ORDER BY [ID] DESC OFFSET 0 ROWS -- sortowanie listy
) AS [InnerData] FOR JSON PATH, INCLUDE_NULL_VALUES
) AS [Data] FOR JSON PATH, INCLUDE_NULL_VALUES
W przypadku wyświetlania sekcji typu lista zapytanie wygląda podobnie. Jeśli jest zdefiniowany warunek zależności od innej sekcji, zastępuje on skonfigurowany filtr dla listy (linie 7 i 21). Zestaw rekordów zwracanych do listy jest sortowany klauzulą ORDER BY w linii 25. W tym warunku wstawiana jest nazwa kolumny sortowania domyślnego, z wybranej konfiguracji listy lub tej, której nagłówek kliknął ostatnio użytkownik we FrontSPA. Sortowanie jest resetowane (do domyślnej konfiguracji wyświetlania) po kliknięciu przycisku resetowania konfiguracji listy (czerwony przycisk z gumką).
Konstrukcja tego zapytania zostanie zoptymalizowana w jednej z kolejnych wersji. Tym niemniej, aby nie powodowało ono problemów z wydajnością, warto stosować się do poniższych zaleceń:
- Dla dużych zestawów danych włączać ustawienie
Funkcja server-side
w definicji listy. - Nie stosować klauzul ORDER BY i OFFSET w zapytaniu źródłowym widoku listy w celu ustawiania domyślnego sortowania.
-
Jeśli zachodzi potrzeba domyślnego sortowania rekordów listy, należy w kreatorze listy w AdminSPA kliknąć nagłówek odpowiedniej kolumny na podglądzie i zapisać definicję (patrz ilustracja poniżej). Jeśli ta kolumna nie ma być widoczna, należy użyć warunku widoczności lub dezaktywować kolumnę. To sortowanie zostanie zapisane jako systemowa konfiguracja listy.
Ustawianie domyślnego sortowania listy
Ponadto należy wprowadzić plan utrzymania kondycji bazy danych poprzez reorganizację lub przebudowę indeksów. W tym celu można skorzystać z poniższego skryptu, który w przyszłych wersjach będzie dostępny jako procedura systemowa.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
DECLARE @table_schema NVARCHAR(MAX)
DECLARE @table_name NVARCHAR(MAX)
DECLARE tables_cursor CURSOR FAST_FORWARD
FOR
SELECT
SCHEMA_NAME(schema_id) as [Schema_Name],
t.name AS Table_Name
FROM sys.tables AS t
ORDER BY
SCHEMA_NAME(schema_id),
t.name;
OPEN tables_cursor
FETCH NEXT FROM tables_cursor
INTO @table_schema, @table_name;
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @index_name NVARCHAR(MAX)
DECLARE @index_fragmentation DECIMAL(18, 2)
DECLARE @table_with_schema NVARCHAR(MAX) = CONCAT('[', @table_schema, ']', '.', '[', @table_name, ']')
PRINT 'Table: ' + @table_with_schema
DECLARE index_cursor CURSOR FAST_FORWARD
FOR
SELECT
idx.[name],
ips.[avg_fragmentation_in_percent]
FROM
sys.dm_db_index_physical_stats(DB_ID(DB_NAME()), OBJECT_ID(@table_with_schema), NULL, NULL, NULL) AS [ips]
INNER JOIN sys.indexes AS [idx] ON [ips].[object_id] = [idx].[object_id] AND [ips].[index_id] = [idx].[index_id]
WHERE ips.[index_id] > 0
OPEN index_cursor
FETCH NEXT FROM index_cursor
INTO @index_name, @index_fragmentation;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'Index: ' + @index_name
PRINT 'Fragmentation: ' + CAST(@index_fragmentation AS NVARCHAR(MAX))
IF (@index_fragmentation BETWEEN 5 AND 30)
BEGIN
DECLARE @reorganizeQuery NVARCHAR(MAX) = 'ALTER INDEX ' + @index_name + ' ON ' + @table_with_schema + ' REORGANIZE'
exec sp_executesql @reorganizeQuery
PRINT 'Index ' + @index_name + ' was reorganized'
END
ELSE IF (@index_fragmentation > 30)
BEGIN
DECLARE @rebuildQuery NVARCHAR(MAX) = 'ALTER INDEX ' + @index_name + ' ON ' + @table_with_schema + ' REBUILD'
exec sp_executesql @rebuildQuery
PRINT 'Index ' + @index_name + ' was rebuilt'
END
FETCH NEXT FROM index_cursor
INTO @index_name, @index_fragmentation;
END
PRINT ''
CLOSE index_cursor;
DEALLOCATE index_cursor;
FETCH NEXT FROM tables_cursor
INTO @table_schema, @table_name;
END
CLOSE tables_cursor;
DEALLOCATE tables_cursor;