אפליקציות אינטרנט מחלקות לעיתים קרובות את הנתונים לדפים כשהן מציגות אותם למשתמשים. משתמש הקצה מקבל דף אחד של תוצאות, וכשהוא עובר לדף הבא, נשלפת ומוצגת קבוצת התוצאות הבאה. בדף הזה מוסבר איך להוסיף מספור עמודים לתוצאות חיפוש כשמבצעים חיפוש טקסט מלא ב-Spanner.
אפשרויות עימוד
יש שתי דרכים להטמיע שאילתות עם חלוקה לדפים ב-Spanner: חלוקה לדפים על סמך מפתח (מומלץ) וחלוקה לדפים על סמך היסט.
החלוקה לדפים לפי מפתח היא שיטה לאחזור תוצאות חיפוש בחלקים קטנים יותר ונוחים יותר לניהול, תוך הבטחה של תוצאות עקביות בכל הבקשות. מזהה ייחודי (ה'מפתח') מהתוצאה האחרונה בדף משמש כנקודת התייחסות לאחזור קבוצת התוצאות הבאה.
בדרך כלל, מומלץ להשתמש ב-Spanner בהחלפה לדף שמבוססת על מפתח. אמנם קל יותר להטמיע חלוקה לדפים שמבוססת על היסט, אבל יש לה שני חסרונות משמעותיים:
- עלות גבוהה יותר של שאילתות:החלוקה לעמודים שמבוססת על היסטוריית המיקום מאחזרת ומוחקת שוב ושוב את אותן תוצאות, מה שמוביל לעלויות גבוהות יותר ולביצועים נמוכים יותר.
- תוצאות לא עקביות: בשאילתות עם חלוקה לדפים, כל דף מאוחזר בדרך כלל עם חותמת זמן שונה של קריאה. לדוגמה, הדף הראשון יכול להיות תוצאה של שאילתה שהוגשה בשעה 13:00, והדף הבא יכול להיות תוצאה של שאילתה שהוגשה בשעה 13:10. המשמעות היא שתוצאות החיפוש יכולות להשתנות בין שאילתות, ולכן התוצאות בדפים לא יהיו עקביות.
לעומת זאת, כשמשתמשים בהחלפה לדף הבא שמבוססת על מפתח, המערכת משתמשת במזהה ייחודי (מפתח) מהתוצאה האחרונה בדף כדי לאחזר את קבוצת התוצאות הבאה. כך מובטחים גם אחזור יעיל וגם תוצאות עקביות, גם אם נתוני הבסיס משתנים.
כדי לספק יציבות בתוצאות הדף, האפליקציה יכולה להנפיק את כל השאילתות לדפים שונים באותה חותמת זמן. עם זאת, יכול להיות שהפעולה תיכשל אם השאילתה חורגת מתקופת השמירה של הגרסה (ברירת המחדל היא שעה אחת). לדוגמה, הכשל הזה קורה אם version_gc הוא שעה אחת, ומשתמש הקצה אחזר את התוצאות הראשונות בשעה 13:00 ולחץ על הבא בשעה 15:00.
שימוש בהחלפת דפים שמבוססת על מפתח
בחלוקה לדפים שמבוססת על מפתח, המערכת זוכרת את הפריט האחרון בדף הקודם ומשתמשת בו כנקודת התחלה לשאילתה של הדף הבא. כדי לעשות את זה, השאילתה צריכה להחזיר את העמודות שצוינו בסעיף ORDER BY ולהגביל את מספר השורות באמצעות LIMIT.
כדי שהחלוקה לדפים לפי מפתח תפעל, השאילתה צריכה למיין את התוצאות לפי סדר כולל קפדני. הדרך הכי קלה היא לבחור סדר כולל ואז להוסיף עמודות להכרעה, אם צריך. ברוב המקרים, הסדר הכולל הוא סדר המיון של אינדקס החיפוש, והשילוב הייחודי של העמודות הוא המפתח הראשי של טבלת הבסיס.
אם משתמשים בסכימה לדוגמה Albums, השאילתה של הדף הראשון תיראה כך:
GoogleSQL
SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 10;
PostgreSQL
SELECT albumid, releasetimestamp
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY releasetimestamp DESC, albumid
LIMIT 10;
ה-AlbumId הוא הגורם להכרעה כי ReleaseTimestamp הוא לא מפתח. יכול להיות שיש שני אלבומים שונים עם אותו ערך של ReleaseTimestamp.
כדי להמשיך, האפליקציה מריצה שוב את אותה שאילתה, אבל עם פסקה WHERE שמגבילה את התוצאות מהדף הקודם. התנאי הנוסף צריך להתייחס לכיוון המפתח (עולה לעומת יורד), לכללי שבירת שוויון ולסדר של ערכי NULL בעמודות שניתן להזין בהן ערכי NULL.
בדוגמה שלנו, AlbumId היא עמודת המפתח היחידה (בסדר עולה) והיא לא יכולה להיות NULL, ולכן התנאי הוא:
GoogleSQL
SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE (ReleaseTimestamp < @last_page_release_timestamp
OR (ReleaseTimestamp = @last_page_release_timestamp
AND AlbumId > @last_page_album_id))
AND SEARCH(AlbumTitle_Tokens, @p)
ORDER BY ReleaseTimestamp DESC, AlbumId ASC
LIMIT @page_size;
PostgreSQL
בדוגמה הזו נעשה שימוש בפרמטרים של שאילתה $1, $2, $3 ו-$4 שמשויכים לערכים שצוינו עבור last_page_release_timestamp, last_page_album_id, query ו-page_size, בהתאמה.
SELECT albumid, releasetimestamp
FROM albums
WHERE (releasetimestamp < $1
OR (releasetimestamp = $1
AND albumid > $2))
AND spanner.search(albumtitle_tokens, $3)
ORDER BY releasetimestamp DESC, albumid ASC
LIMIT $4;
מערכת Spanner מפרשת את סוג התנאי הזה כ-seekable. המשמעות היא ש-Spanner לא קורא את האינדקס עבור מסמכים שאתם מסננים. האופטימיזציה הזו היא מה שהופך את ההחלפה לדפים שמבוססת על מפתח ליעילה הרבה יותר מהחלפה לדפים שמבוססת על היסט.
שימוש בהחלפה לדף הבאה שמבוססת על היסט
החלוקה לדפים שמבוססת על היסט משתמשת בסעיפים LIMIT ו-OFFSET של שאילתת SQL כדי לדמות דפים. הערך LIMIT מציין את מספר התוצאות בדף.
הערך OFFSET מוגדר לאפס בדף הראשון, לגודל הדף בדף השני ולגודל הדף כפול 2 בדף השלישי.
לדוגמה, השאילתה הבאה מאחזרת את הדף השלישי, עם גודל דף של 50:
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 50 OFFSET 100;
PostgreSQL
SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY releasetimestamp DESC, albumid
LIMIT 50 OFFSET 100;
הערות לשימוש:
- מומלץ מאוד להשתמש בסעיף
ORDER BYכדי להבטיח סדר עקבי בין הדפים. - בשאילתות של ייצור, משתמשים בפרמטרים של שאילתה ולא בקבועים כדי לציין את
LIMITואתOFFSET, כדי לשפר את היעילות של שמירת השאילתה במטמון. מידע נוסף מופיע במאמר בנושא פרמטרים של שאילתות.
המאמרים הבאים
- איך לדרג את תוצאות החיפוש
- איך מבצעים חיפוש של מחרוזת משנה
- איך משלבים שאילתות של טקסט מלא עם שאילתות של טקסט חלקי
- איך מחפשים בכמה עמודות