Nota techniczna
z dn. 16-05-2025

PDF

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ń:

  1. Dla dużych zestawów danych włączać ustawienie Funkcja server-side w definicji listy.
  2. Nie stosować klauzul ORDER BY i OFFSET w zapytaniu źródłowym widoku listy w celu ustawiania domyślnego sortowania.
  3. 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
    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;



Copyright © 2025 OPTEAM SA. Theme Copyright © 2017-2020 Patrick Marsceill. Distributed by an MIT license.