İndi isə gəlin pəncərə funksiyaları ilə işləyərkən ortaya çıxa biləcək çətinliklərdən danışaq. Hər zamanki kimi, proqramlaşdırmada (və həyatda) başqalarının səhvlərindən öyrənmək daha yaxşıdır. İndi həm yeni başlayanların, həm də bəzən təcrübəli developerlərin yol verdiyi tipik səhvləri müzakirə edəcəyik və onlardan necə qaçmaq lazım olduğunu öyrənəcəyik.
Səhv №1: PARTITION BY-dan düzgün istifadə etməmək
Ən çox rast gəlinən səhvlərdən biri — PARTITION BY parametrini unutmaq və ya səhv yazmaqdır, xüsusilə də datanı qruplara bölmək istəyəndə. Onsuz PostgreSQL bütün sətirləri bir böyük qrup kimi götürəcək və nəticələr gözlədiyiniz kimi olmayacaq.
Tutaq ki, bizdə sales adlı bir cədvəl var və burada satışlar haqqında məlumat saxlanılır:
| id | region | month | total |
|---|---|---|---|
| 1 | North | 2023-01 | 1000 |
| 2 | South | 2023-01 | 800 |
| 3 | North | 2023-02 | 1200 |
| 4 | South | 2023-02 | 900 |
Hər region üçün aylara görə yığılan cəmi (SUM()) tapmaq istəyirsən. Belə bir sorğu yaza bilərsən:
SELECT
region,
month,
SUM(total) OVER (ORDER BY month) AS running_total
FROM
sales;
Nəticə:
| region | month | running_total |
|---|---|---|
| North | 2023-01 | 1000 |
| South | 2023-01 | 1800 |
| North | 2023-02 | 3000 |
| South | 2023-02 | 3900 |
İlk baxışda hər şey qaydasındadır. Amma nəticə gözlədiyimiz kimi deyil, çünki yığılan cəm regionlara görə yox, bütün sətirlər üçün hesablanır. Problem ondadır ki, PARTITION BY region əlavə etməyi unutmuşuq.
Düzgün kod:
SELECT
region,
month,
SUM(total) OVER (PARTITION BY region ORDER BY month) AS running_total
FROM
sales;
Nəticə:
| region | month | running_total |
|---|---|---|
| North | 2023-01 | 1000 |
| North | 2023-02 | 2200 |
| South | 2023-01 | 800 |
| South | 2023-02 | 1700 |
İndi hər şey düz işləyir: datalar regionlara görə qruplaşdırılır və yığılan cəm hər region üçün ayrıca hesablanır.
Səhv №2: ORDER BY-da düzgün sıralama verməmək
ORDER BY OVER() içində pəncərə daxilində sətirlərin sırasını təyin edir. Əgər sıralama səhvdirsə, nəticələr də gözlənilməz olacaq.
Satışların yığılan cəmini ayların azalan sırasına görə tapmaq istəyirsən. Belə bir sorğu yaza bilərsən:
SELECT
month,
total,
SUM(total) OVER (ORDER BY month DESC) AS running_total
FROM
sales;
Nəticə:
| month | total | running_total |
|---|---|---|
| 2023-02 | 1200 | 1200 |
| 2023-02 | 900 | 2100 |
| 2023-01 | 1000 | 3100 |
| 2023-01 | 800 | 3900 |
İlk baxışda düz görünür, amma diqqət et: sətirlər aylar üzrə qruplaşıb, amma cəmlər düzgün hesablanmayıb, çünki sıralama azalan verilib. Ona görə nəticələr qarışıq çıxır.
Düzəliş: sorğunu düzgün ORDER BY ilə yaz:
SELECT
month,
total,
SUM(total) OVER (ORDER BY month ASC) AS running_total
FROM
sales;
Səhv №3: Pəncərə funksiyalarını indeks olmadan istifadə etmək
Pəncərə funksiyaları çox vaxt böyük həcmli datalarla işləyir və əsas sütunlarda indeks yoxdursa, performans bərbad ola bilər.
Nümunə: bizdə milyonlarla sətri olan large_sales cədvəli var və satışların rank-larını hesablamaq istəyirik:
SELECT
id,
total,
RANK() OVER (ORDER BY total DESC) AS rank
FROM
large_sales;
Az datada sorğu tez işləyəcək, amma böyük həcmdə bu, sonsuz çəkə bilər.
Düzəliş: ORDER BY-da istifadə olunan sütunda indeks yarat:
CREATE INDEX idx_total ON large_sales(total DESC);
İndi sorğu xeyli tez işləyəcək.
Səhv №4: ROWS və ya RANGE ilə pəncərənin necə işlədiyini başa düşməmək
ROWS və RANGE istifadə edəndə, onların pəncərəni necə hesablamağını başa düşmək vacibdir. Bu açar sözləri səhv başa düşsən, nəticələr gözlənilməz olacaq.
Nümunə: indiki ay və əvvəlki iki ay üçün satışların hərəkətli ortasını hesablamaq istəyirsən:
SELECT
month,
AVG(total) OVER (ORDER BY month ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg
FROM
sales;
Əgər ROWS əvəzinə RANGE yazsan:
SELECT
month,
AVG(total) OVER (ORDER BY month RANGE BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg
FROM
sales;
Nəticə fərqli olacaq, çünki RANGE konkret sətir sayına yox, dəyər aralığına baxır.
Səhv №5: Pəncərə funksiyalarından həddindən artıq istifadə
Bir sorğuda bir neçə pəncərə funksiyası istifadə etmək hesablamaların təkrarlanmasına və performansın düşməsinə səbəb ola bilər.
Nümunə:
SELECT
id,
total,
SUM(total) OVER (PARTITION BY region) AS region_total,
SUM(total) OVER (PARTITION BY region) / COUNT(total) OVER (PARTITION BY region) AS region_avg
FROM
sales;
Burada SUM(total) və COUNT(total) hər sətir üçün bir neçə dəfə hesablanır.
Düzəliş: sorğunu alt-sorğular və ya CTE ilə qısalt:
WITH cte_region_totals AS (
SELECT
region,
SUM(total) AS region_total,
COUNT(total) AS region_count
FROM
sales
GROUP BY
region
)
SELECT
s.id,
s.total,
t.region_total,
t.region_total / t.region_count AS region_avg
FROM
sales s
JOIN
cte_region_totals t ON s.region = t.region;
Səhvlərdən qaçmaq üçün məsləhətlər
PARTITION BY və ORDER BY-ı yoxla: həmişə pəncərənin düzgün verildiyinə əmin ol.
Dataları indekslə: xüsusilə sıralama (ORDER BY) və ya filtrasiya istifadə edirsənsə.
Çoxlu hesablamalar üçün CTE istifadə et: bu, təkrarlanan addımları azaltmağa kömək edəcək.
İcra planına bax: sorğunu PostgreSQL necə işlədiyini başa düşmək üçün EXPLAIN və EXPLAIN ANALYZE istifadə et.
Real datada test et: nəticələrin gözləntilərinə uyğun olduğuna və tapşırığın düzgün həll olunduğuna əmin ol.
GO TO FULL VERSION