29. البحث عن أقرب جار

29.2. الربط بأقرب جار

لمعامل الترتيب المدعوم بالفهرس عيب رئيسي واحد: فهو لا يعمل إلا مع شكل هندسي حرفي واحد على أحد جانبي المعامل. هذا مناسب لإيجاد أقرب الكائنات إلى كائن استعلام واحد، لكنه لا يفيد في الربط المكاني، حيث يكون الهدف إيجاد أقرب جار لكل عنصر في مجموعة كاملة من المرشّحين.

لحسن الحظ، هناك ميزة في لغة SQL تتيح لنا تشغيل استعلام بشكل متكرر داخل حلقة: ربط LATERAL.

سنعثر هنا على أقرب شارع لكل محطة مترو:

SELECT subways.gid AS subway_gid,
       subways.name AS subway,
       streets.name AS street,
       streets.gid AS street_gid,
       streets.geom::geometry(MultiLinestring, 26918) AS street_geom,
       streets.dist
FROM nyc_subway_stations subways
CROSS JOIN LATERAL (
  SELECT streets.name, streets.geom, streets.gid, streets.geom <-> subways.geom AS dist
  FROM nyc_streets AS streets
  ORDER BY dist
  LIMIT 1
) streets;

لاحظ كيف يعمل CROSS JOIN LATERAL بوصفه الجزء الداخلي من حلقة يقودها جدول المترو. إذ يُمرَّر كل سجل في جدول المترو إلى الاستعلام الفرعي الجانبي (lateral)، سجلًا تلو الآخر، فتحصل على أقرب نتيجة لكل سجل من سجلات المترو.

_images/knn4.png

تُظهر خطة التنفيذ (explain) الحلقة على محطات المترو، والترتيب المدعوم بالفهرس داخل الحلقة حيث نريده:

                           QUERY PLAN
-------------------------------------------------------------------------
 Nested Loop  (cost=0.28..13140.71 rows=491 width=37)
   ->  Seq Scan on nyc_subway_stations subways
       (cost=0.00..15.91 rows=491 width=46)
   ->  Limit
       (cost=0.28..1.71 rows=1 width=170)
         ->  Index Scan using nyc_streets_geom_idx on nyc_streets streets
             (cost=0.28..27410.12 rows=19091 width=170)
                Order By: (geom <-> subways.geom)