Changes between Initial Version and Version 1 of OtherTopics


Ignore:
Timestamp:
09/25/26 05:48:36 (6 days ago)
Author:
223306
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • OtherTopics

    v1 v1  
     1= Other Topics =
     2
     3== SQL Performance ==
     4
     5Во оваа фаза беше направена анализа на перформансите на SQL пребарувања кои се користат во BiblioPremium. Анализата беше направена со EXPLAIN ANALYZE пред и после креирање на предложените индекси.
     6
     7=== 1. Анализа на продажба по книги ===
     8
     9Анализирано е комплексно пребарување кое ги прикажува вкупно продадените примероци и вкупниот приход по книга за завршени нарачки.
     10
     11{{{
     12EXPLAIN ANALYZE
     13SELECT
     14    k.kniga_id,
     15    k.naslov,
     16    SUM(s.kolicina) AS vkupno_prodadeni,
     17    SUM(s.kolicina * s.edinechna_cena) AS vkupen_prihod
     18FROM project.knigi k
     19JOIN project.sodrzi s
     20    ON k.kniga_id = s.kniga_id
     21JOIN project.naracki n
     22    ON s.naracka_id = n.naracka_id
     23WHERE n.status = 'ZAVRSENA'
     24GROUP BY k.kniga_id, k.naslov
     25ORDER BY vkupen_prihod DESC;
     26}}}
     27
     28Пред креирање на индексот, execution plan покажа Sequential Scan (Seq Scan) на табелата naracki при филтрирањето според статусот ZAVRSENA.
     29
     30За оптимизација беше предложен и креиран следниот индекс:
     31
     32{{{
     33CREATE INDEX idx_naracki_status
     34ON project.naracki(status);
     35}}}
     36
     37По креирањето на индексот повторно беше извршен EXPLAIN ANALYZE.
     38
     39PostgreSQL и понатаму избра Sequential Scan на табелата naracki и индексот idx_naracki_status не беше употребен.
     40
     41Причината е малиот број записи во табелата. За мала табела PostgreSQL проценува дека директното секвенцијално читање е поевтино од пристап преку индекс. Индексот може да стане покорисен со значително зголемување на бројот на нарачки.
     42
     43Заклучок: индексот е соодветен кандидат за поголема количина на податоци, но кај моменталната мала тест база оптимизаторот правилно избира Sequential Scan.
     44
     45=== 2. Препораки според расположение ===
     46
     47Беше анализирано пребарувањето за пронаоѓање достапни книги поврзани со избрано расположение.
     48
     49{{{
     50EXPLAIN ANALYZE
     51SELECT
     52    k.kniga_id,
     53    k.naslov,
     54    k.cena,
     55    k.kolicina_na_zaliha
     56FROM project.knigi k
     57JOIN project.povrzana_so ps
     58    ON k.kniga_id = ps.kniga_id
     59WHERE ps.raspolozenie_id = 1
     60  AND k.kolicina_na_zaliha > 0
     61ORDER BY k.naslov;
     62}}}
     63
     64Execution plan покажа дека PostgreSQL веќе користи постоечки индекс:
     65
     66{{{
     67Bitmap Index Scan on povrzana_so_pkey
     68Index Cond: (raspolozenie_id = 1)
     69}}}
     70
     71Измереното време на извршување беше приближно 0.132 ms.
     72
     73Поради тоа не беше креиран дополнителен индекс, бидејќи постоечкиот индекс веќе се користи при пребарувањето. Додавање непотребен индекс би создало дополнителен трошок при INSERT/UPDATE операции без значителна корист за моменталниот обем на податоци.
     74
     75=== 3. Пребарување книги по наслов ===
     76
     77Апликацијата овозможува пребарување на книги според наслов. Беше анализирано пребарување со делумно совпаѓање на текстот:
     78
     79{{{
     80EXPLAIN ANALYZE
     81SELECT
     82    kniga_id,
     83    naslov,
     84    cena,
     85    kolicina_na_zaliha
     86FROM project.knigi
     87WHERE LOWER(naslov) LIKE '%work%'
     88ORDER BY naslov;
     89}}}
     90
     91Пред креирањето на индексот беше добиен:
     92
     93{{{
     94Seq Scan on knigi
     95Execution Time: 0.075 ms
     96}}}
     97
     98За поддршка на пребарување со шаблон од типот '%text%' беше активирана PostgreSQL екстензијата pg_trgm:
     99
     100{{{
     101CREATE EXTENSION IF NOT EXISTS pg_trgm;
     102}}}
     103
     104Потоа беше креиран GIN trigram индекс:
     105
     106{{{
     107CREATE INDEX idx_knigi_naslov_trgm
     108ON project.knigi
     109USING gin (LOWER(naslov) gin_trgm_ops);
     110}}}
     111
     112По креирањето на индексот повторно беше извршен истиот EXPLAIN ANALYZE.
     113
     114Резултат:
     115
     116{{{
     117Seq Scan on knigi
     118Execution Time: 0.063 ms
     119}}}
     120
     121Индексот не беше употребен во execution plan. Табелата моментално содржи многу мал број книги, поради што PostgreSQL проценува дека Sequential Scan е поевтин.
     122
     123Иако измереното време после креирањето на индексот беше 0.063 ms наспроти 0.075 ms пред индексот, оваа разлика не се припишува на индексот бидејќи execution plan покажува дека индексот не бил употребен.
     124
     125Со значително поголем каталог на книги, trigram индексот е наменет да овозможи поефикасно пребарување со делумно совпаѓање на текст.
     126
     127== Security measures ==
     128
     129=== Application security ===
     130
     131Во апликацијата се применети повеќе мерки за заштита на пристапот до базата и податоците.
     132
     133'''1. Заштита од SQL Injection'''
     134
     135SQL пребарувањата користат параметризирани вредности преку psycopg2 placeholders (%s), наместо директно спојување на корисничкиот внес со SQL текстот.
     136
     137Пример:
     138
     139{{{
     140cursor.execute("""
     141    SELECT kniga_id, naslov, cena, opis, godina_izdavanje
     142    FROM project.knigi
     143    WHERE naslov ILIKE %s
     144    ORDER BY kniga_id;
     145""", (f"%{search}%",))
     146}}}
     147
     148На овој начин внесот од корисникот се испраќа како SQL параметар, а не како дел од SQL командата.
     149
     150'''2. Автентикација и кориснички сесии'''
     151
     152По успешна најава во Flask session се зачувуваат идентификаторот и улогата на корисникот. Заштитените функционалности проверуваат дали постои најавен корисник.
     153
     154'''3. Авторизација според улога'''
     155
     156Административните страници и операции се достапни само за корисници со улога ADMIN.
     157
     158Пример:
     159
     160{{{
     161if "korisnik_id" not in session:
     162    return redirect(url_for("login"))
     163
     164if session.get("uloga") != "ADMIN":
     165    return redirect(url_for("home"))
     166}}}
     167
     168Оваа проверка се користи кај административниот панел и административните операции за книги, жанрови, категории, расположенија, нарачки и плаќања.
     169
     170'''4. Ограничување на пристап до кориснички податоци'''
     171
     172При прикажување на нарачките, податоците се филтрираат според korisnik_id од активната сесија.
     173
     174{{{
     175WHERE n.korisnik_id = %s
     176}}}
     177
     178И при прикажување на успешно купување се проверуваат и naracka_id и korisnik_id, со што најавениот корисник не може преку промена на ID во URL да пристапи до нарачка на друг корисник.
     179
     180'''5. Трансакциска заштита'''
     181
     182Кај операции кои менуваат повеќе табели, како купување книга и зачувување преференции, се користат commit и rollback.
     183
     184При успешна операција:
     185
     186{{{
     187conn.commit()
     188}}}
     189
     190При грешка:
     191
     192{{{
     193conn.rollback()
     194}}}
     195
     196Со ова се спречува делумно зачувување на податоци при неуспешна операција.
     197
     198'''6. Заштита на параметрите за поврзување'''
     199
     200Податоците за поврзување со PostgreSQL и SSH (корисничко име, лозинка и други параметри) се земаат од environment variables преку .env датотека, наместо да бидат директно запишани во изворниот код.
     201
     202=== Database security ===
     203
     204Апликацијата пристапува до проектната PostgreSQL база преку автентициран database account.
     205
     206Со:
     207
     208{{{
     209SELECT current_user;
     210}}}
     211
     212беше потврдено дека конекцијата се извршува преку проектниот database owner account.
     213
     214Пристапот до PostgreSQL се реализира преку SSH tunnel, а credentials се вчитуваат од environment variables.
     215
     216SQL командите кои содржат вредности добиени од апликацијата користат параметризирани SQL изрази. Во апликацијата не се користи динамичко составување SQL команди преку директно додавање на кориснички внес.
     217
     218Дополнително, интегритетот на податоците се поддржува со примарни и надворешни клучеви, ограничувања и релации дефинирани во базата.
     219
     220=== Ограничувања и можни идни подобрувања ===
     221
     222Во моменталниот прототип корисничките лозинки не се хешираат пред зачувување. Во продукциска верзија треба да се користи сигурен password hashing механизам.
     223
     224Flask secret key моментално е дефиниран во апликацискиот код. Во продукциска околина треба да се премести во environment variable и да се користи силна случајно генерирана вредност.
     225
     226Исто така, апликацијата моментално се поврзува преку проектниот database owner account. Дополнително подобрување би било креирање посебна database улога за апликацијата со минималните потребни привилегии.
     227
     228== Other developments ==
     229
     230Во рамките на претходните фази се имплементирани дополнителни механизми кои придонесуваат за перформанси, интегритет и сигурност на системот:
     231
     232* connection pooling за повторна употреба на PostgreSQL конекции;
     233* трансакции со commit/rollback;
     234* trigger за проверка и намалување на залиха;
     235* database views за продажба и следење на ниска залиха;
     236* database function за препорака на книги според расположение;
     237* административна авторизација според улога;
     238* проверки пред бришење на податоци кои се поврзани со други записи.