# VC-093 · Sık süzülen ve RLS politikasında kullanılan sütunda uygun indeks bulunmuyor

Liste az satır döndürse bile veritabanı sonucu bulmak için çok sayıda kaydı tarıyor. Sık kullanılan filtreye uygun indeks olmayınca veri ve istek sayısıyla birlikte sorgunun maliyeti büyüyor.

- Önem: ORTA. Etkisi orta. Trafik artınca ya da istek tekrarlanınca tetiklenir.
- Önem notu: Büyüyen tabloda seçici ve sık çalışan sorgu temel alınır. Küçük tabloda tam tarama doğru tercih olabilir. Yetkiyi kaldırmak performans düzeltmesi sayılmaz, ayrı veri erişimi riski yaratır.
- Eksen ve kategori: Sağlamlık, 14 Performans ve ölçek
- Yığın: Supabase
- Yapay zekâ kodunda: ölçülmedi. Dayanak: uzman görüşü.
- Ne zaman bakılır: İlk yayından önce, Her ay
- CWE: CWE-1067
- Checklist ifadesi: Sık süzülen ve RLS politikasında kullanılan sütunlarda uygun indeks var.
- Son inceleme: 4 Ekim 2026, Komünite editörlüğü
- Adres: https://vibecheck.komunite.com.tr/madde/sik-filtre-ve-rls-sutunlarinda-uygun-indeks-yok

## 60 saniyelik kontrol

Yalnız kendi uygulamanda ya da yazılı izin aldığın sistemde dene. Bu bir sızma testi değildir.

1. Yavaş sorgunun gerçek kullanıcı rolü ve filtreleriyle planını incele.
2. RLS politikasındaki sütunları ve mevcut indekslerin sırasını karşılaştır.
3. Az satır dönen sorgunun kaç satır taradığını kontrol et.
4. İndeks değişince aynı kullanıcının aynı kayıtları gördüğünü doğrula.

## Ne oluyor

Liste yalnız sana ait kayıtları gösteriyor ve sayfa boyutu da sınırlı. Bu iki doğru karar sorgunun ucuz olduğunu düşündürüyor. Oysa veritabanı o kayıtları bulmak için tablonun geniş bölümüne bakabilir. Sonuçta az satır bulunması, arama sırasında az iş yapıldığını göstermez. Sahip sütununda uygun indeks yoksa tablo büyüdükçe aynı ekran daha çok iş ister.

RLS, satır düzeyindeki erişim politikasıdır. Kullanıcının hangi kaydı görebileceğini belirleyen ifade sorgunun çalışma koşullarına katılır. Yönetici hesabıyla yaptığın hızlı sorgu bu politikanın maliyetini göstermeyebilir. Uygulama rolünün kimliği, filtreleri ve veri dağılımı birlikte değerlendirilmelidir. İndeks adının şemada bulunması da yeterli olmaz. İndeksin sütun sırası veya kapsadığı ifade, çalışan sorgunun ihtiyacından farklı olabilir.

Örnekte sahip kimliğiyle süzülen liste kayıt kimliğine göre sıralanıyor. Birleşik indeks bu erişim yolunu destekliyor. Buradaki hüküm her sütuna indeks eklemek değil. Sık kullanılan sorgunun gereksiz tarama yapıp yapmadığını gerçek planıyla görmek ve yalnız gerekliyse uygun erişim yolunu kurmaktır.

## Gerçek olay

Bu madde belirli bir AI uygulamasının kamuya açık kesinti kaydına dayanmıyor. Supabase, RLS performansı için politikada kullanılan sütunların indekslenmesini ve uygulama kullanıcısının koşullarıyla ölçüm yapılmasını öneriyor. Belgedeki örnek sonuçları senin tablon için süre garantisi olarak aktarmıyoruz. [RLS performans rehberi](https://supabase.com/docs/guides/database/postgres/row-level-security-performance)

PostgreSQL planlayıcısı tablo istatistiklerine ve sorguya göre erişim yolu seçer. Küçük tabloda tam tarama makul olabilir. Çok sütunlu indeksin hangi koşullarda yarar sağladığı sütun sırasına ve karşılaştırma türüne bağlıdır. [Birleşik indeksler](https://www.postgresql.org/docs/current/indexes-multicolumn.html) Bu nedenle maddeyi yalnız indeks eksikliğiyle otomatik açık saymıyoruz. CWE-1067, veri kaynağında aşırı sıralı arama desenini tarif ediyor. Buradaki eşleme bir kesinti yaşandığı veya saldırının kanıtlandığı anlamına gelmiyor. [CWE-1067](https://cwe.mitre.org/data/definitions/1067.html)

## Yapay zekâ bunu neden üretiyor

**Model görünür sonucu tamamlar.** İstemde kullanıcının kendi kayıtlarını görmesi anlatıldığında ajan tabloyu, politikayı ve listeyi kurabilir. Ekranın doğru görünmesi görevin tamamlandığı izlenimini verir. Ancak sorgunun kaç kayıt incelediği ekranda görünmez. Temsil edici veri dağılımı ve sorgu bütçesi istenmediyse bu ikinci boyut çözümün dışında kalabilir.

**Küçük örnek veri farkı örter.** Geliştirme tablosunda az kayıt varsa indeksli ve indekssiz sürüm aynı hızda hissedilebilir. Ajan bu ortamdan üretim boyutuna dair sonuç çıkarırsa yanlış güven oluşur. Sorun modelin tek başına SQL yazması kadar, kabul ölçütünün yalnız dönen satırlara bağlanmasıdır. Veri hacmi ve sahipler arasındaki dağılım da örneğe eklenmelidir.

**Ayrı görevler ortak sorguyu gizler.** RLS politikası bir turda, sıralama başka turda yazılabilir. Her parça kendi başına anlaşılırken birleşik sorgunun erişim yolu incelenmez. Sonradan yalnız kimlik sütununda görülen bir indeks bütün filtreleri karşılıyormuş gibi yorumlanabilir. İnceleme indeks adlarını saymak yerine gerçek filtre ve sıralamayı takip etmelidir.

**Hız isteği yetkiyi tartışmaya açabilir.** Yavaş sorguya çözüm aranırken politikayı kaldırmak kolay bir değişiklik olarak önerilebilir. Bu değişiklik ölçülen işi azaltırken erişim sözleşmesini de değiştirir. Ajanın kabul ölçütüne görünür kayıtların aynı kalması eklenmelidir. Bunlar olası üretim mekanizmalarına ilişkin yorumlardır. Modellerin bu hatayı hangi sıklıkta yaptığını gösteren bir ölçüm sunmuyoruz.

## Etki

Tek liste isteğinin gereksiz taraması, aynı anda çalışan diğer sorgulara ayrılan kaynakları azaltabilir. Kullanıcı bekler, süre sınırına ulaşan istekler hata verir ve yeniden denemeler yükü artırabilir. Darboğazı yalnız sunucu boyutuyla çözmek ek maliyet yaratabilir.

Öte yandan gereksiz indeksler de depolama ve yazma işi ekler. Her okuma sorunu için bütün sütunları indekslemek bu maliyeti büyütür. Ölçülen sorgu, beklenen yük ve yazma yoğunluğu birlikte değerlendirilir. Etki notu büyüyen, seçici ve sık kullanılan listeyi esas alır.

## Nasıl anlarsın

Önce yavaş ekranın gönderdiği sorguyu bul. Sıralama, filtre, sayfa sınırı ve uygulama rolünü kaydet. Temsil edici yerel veride `EXPLAIN` ile planı incele. `EXPLAIN ANALYZE` sorguyu gerçekten çalıştırır. Yazma sorgusunda veya yükü bilinmeyen canlı veride gelişigüzel kullanma. [Plan inceleme](https://www.postgresql.org/docs/current/using-explain.html)

Örneğin testi PostgreSQL üzerinde normal kullanıcı rolüyle çalışır. İndeksin seçilen planda görünmesini ve iki kullanıcının yalnız kendi kayıtlarını görmesini denetler. Kötü sürüm indeks beklentisinde kalır. Bu test süre ölçümü değildir ve her veri dağılımında aynı planı zorlamaz.

## Nasıl düzeltirsin

1. **Sorguyu sabitle.** Aynı rol, filtre ve veri dağılımıyla başlangıç planını sakla. Sonuç kümesini de kaydet.
2. **Erişim yolunu seç.** Örnekte sahip eşitliği ve kimlik sırası için birleşik indeks kullanılır. Kendi sorgunun koşullarını buna körü körüne benzetme.
3. **Kurulumu planla.** Canlı tabloya indeks eklemek kilit ve kaynak etkisi yaratır. Eşzamanlı kurulumun koşulları ve başarısız kurulum sonrası durum ayrı değerlendirilmelidir. [CREATE INDEX](https://www.postgresql.org/docs/current/sql-createindex.html)
4. **Yetkiyi yeniden doğrula.** İndeks sonrası görünür kayıtların değişmediğini, başka sahibin kaydının gelmediğini ve normal listenin çalıştığını kontrol et.

## Bir daha olmasın

Sık kullanılan sorgunun planını, veri büyümesiyle birlikte yeniden incele. Performans düzeltmesinin kabul koşuluna mevcut yetki sınırının korunmasını ekle.

## Sınır

Bu madde eksik sayfalama, satır başına ayrı sorgu veya yanlış RLS politikasını çözmez. Küçük tabloda tam tarama tek başına bulgu değildir. SQL örneği boş yerel test veritabanı içindir ve sentetik tabloyu temizler. Plan döndüren yardımcı fonksiyonu canlı Data API'ye açma. Testteki indeks kullanımı üretim gecikmesinin ölçüldüğü anlamına gelmez.

## Düzeltme kodları

### Supabase: RLS altında sorgu planı

Önce:

```sql
-- supabase/tests/indeks.sql, açıklama amaçlı. Yalnız boş yerel test veritabanında.
create table if not exists public.vc93_items (
  id integer primary key, user_id uuid not null, title text not null
);
truncate public.vc93_items;
insert into public.vc93_items
select g, case when g % 1000 = 0
  then '00000000-0000-0000-0000-000000000001'::uuid
  else '00000000-0000-0000-0000-000000000002'::uuid end, 'Yapay kayıt'
from generate_series(1, 20000) g;
alter table public.vc93_items enable row level security;
drop policy if exists vc93_owner on public.vc93_items;
create policy vc93_owner on public.vc93_items for select to authenticated
  using (user_id = (select auth.uid()));
grant select on public.vc93_items to authenticated;
-- Birincil anahtar indeksi var, sahip filtresini destekleyen indeks yok.
drop index if exists public.vc93_owner_id_idx;
analyze public.vc93_items;
create or replace function public.vc93_plan() returns json
language plpgsql security invoker set search_path = '' as $$
declare result json;
begin
  execute 'explain (format json) select id from public.vc93_items
    where user_id = (select auth.uid()) order by id limit 20' into result;
  return result;
end $$;
revoke all on function public.vc93_plan() from public;
grant execute on function public.vc93_plan() to authenticated;
-- Plan yardımcısı yalnız test içindir, canlı Data API'ye açılmaz.
```

Sonra:

```sql
-- supabase/tests/indeks.sql, açıklama amaçlı. Yalnız boş yerel test veritabanında.
create table if not exists public.vc93_items (
  id integer primary key, user_id uuid not null, title text not null
);
truncate public.vc93_items;
insert into public.vc93_items
select g, case when g % 1000 = 0
  then '00000000-0000-0000-0000-000000000001'::uuid
  else '00000000-0000-0000-0000-000000000002'::uuid end, 'Yapay kayıt'
from generate_series(1, 20000) g;
alter table public.vc93_items enable row level security;
drop policy if exists vc93_owner on public.vc93_items;
create policy vc93_owner on public.vc93_items for select to authenticated
  using (user_id = (select auth.uid()));
grant select on public.vc93_items to authenticated;
-- Eşitlik filtresi ve aynı sahibin sıralı kimlikleri için birleşik indeks.
create index if not exists vc93_owner_id_idx on public.vc93_items(user_id, id);
analyze public.vc93_items;
create or replace function public.vc93_plan() returns json
language plpgsql security invoker set search_path = '' as $$
declare result json;
begin
  execute 'explain (format json) select id from public.vc93_items
    where user_id = (select auth.uid()) order by id limit 20' into result;
  return result;
end $$;
revoke all on function public.vc93_plan() from public;
grant execute on function public.vc93_plan() to authenticated;
-- Canlı indeks kurulumu ayrı migration ve kilit etkisi değerlendirmesi ister.
```

Düzeltmeyi kanıtlayan test:

```sql
-- supabase/tests/indeks.test.sql, açıklama amaçlı. pgTAP ve yerel auth fixture.
begin;
select plan(4);
set local role authenticated;
set local request.jwt.claims = '{"sub":"00000000-0000-0000-0000-000000000001"}';
select is((select count(*) from public.vc93_items), 20::bigint,
  'A yalnız kendi kayıtlarını görür');
select is_empty($q$select id from public.vc93_items
  where user_id = '00000000-0000-0000-0000-000000000002'$q$,
  'açık filtre RLS sınırını açmaz');
select matches(public.vc93_plan()::text, 'vc93_owner_id_idx',
  'bu veri dağılımında plan sahip indeksini kullanır');
set local request.jwt.claims = '{"sub":"00000000-0000-0000-0000-000000000002"}';
select is((select count(*) from public.vc93_items), 19980::bigint,
  'B kendi kayıtlarını okumaya devam eder');
reset role;
select * from finish();
rollback;
```

## Ajan kuralı (AGENTS.md)

```md
## Sorgu gereksiz satır tarıyor (vibecheck VC-093)
- Sık sorguları gerçek uygulama rolüyle ölç.
- Filtre ve sıralamaya uygun indeks seç.
- RLS politikasını hız için kaldırma.
- İndeks sonrası planı ve görünür kayıtları karşılaştır.
- Canlı indeks kurulumunun kilit ve yazma maliyetini değerlendir.
```

## Kaynaklar

1. [RLS performance and best practices](https://supabase.com/docs/guides/database/postgres/row-level-security-performance), Supabase
2. [Multicolumn Indexes](https://www.postgresql.org/docs/current/indexes-multicolumn.html), PostgreSQL
3. [Using EXPLAIN](https://www.postgresql.org/docs/current/using-explain.html), PostgreSQL
4. [CREATE INDEX](https://www.postgresql.org/docs/current/sql-createindex.html), PostgreSQL
5. [CWE-1067 Excessive Execution of Sequential Searches of Data Resource](https://cwe.mitre.org/data/definitions/1067.html), MITRE

---

vibecheck · Komünite editörlüğü. Metin CC BY 4.0, prompt ve kural parçaları MIT-0. Kaynak: https://vibecheck.komunite.com.tr/madde/sik-filtre-ve-rls-sutunlarinda-uygun-indeks-yok
