חיבור אחד, הרבה קבצים
חיבור ל-SQLite לא נעול לקובץ אחד. עם ATTACH DATABASE, אפשר לפתוח קבצי .db נוספים לצד הקובץ שהתחלתם איתו, ולתשאל את כולם כאילו היו סכמות בתוך מסד נתונים אחד. זה הדבר הכי קרוב שיש ל-SQLite ל"כמה מסדי נתונים על שרת אחד".
הצורה הבסיסית:
הקובץ archive.db נוצר אם הוא לא קיים, בדיוק כמו מסד הנתונים הראשי. מעכשיו, בסשן הזה, כל מה שמתחיל בקידומת archive. נמצא בקובץ השני. כל מה שמתחיל ב-main. (או בלי קידומת) נמצא בקובץ המקורי.
לחיבור שלכם יש תמיד שתי סכמות מובלעות: main (הקובץ שפתחתם ראשון) ו-temp (מרחב עבודה לטבלאות זמניות). צירוף מוסיף עוד.
התחביר ומה הכינוי עושה
ATTACH DATABASE 'path/to/file.db' AS alias_name;
הכינוי הוא שם הסכמה שבו תשתמשו כדי לציין טבלאות. הוא מקומי לחיבור הנוכחי: חיבור אחר שמצרף את אותו קובץ יכול לבחור כינוי אחר. בחרו משהו קצר ותיאורי (archive, analytics, cache), כי תקלידו אותו הרבה.
כמה דברים שכדאי לדעת:
- הנתיב יחסי לתיקיית העבודה של התהליך, אלא אם הוא מוחלט.
- המחרוזת
':memory:'מצרפת מסד נתונים בזיכרון חדש תחת הכינוי הזה. - הכינוי לא יכול להתנגש עם
mainאוtemp, ולא יכול לחזור על עצמו בין צירופים.
JOIN בין מסדי נתונים
זו התכונה שבגללה רוב האנשים מצרפים. ברגע ששני קבצים נמצאים באותו חיבור, אפשר לצרף את הטבלאות שלהם בשאילתה אחת:
מתכנן השאילתות מתייחס לשתי הסכמות בדיוק כמו לטבלאות ב-main. נעשה שימוש באינדקסים על טבלאות מצורפות. EXPLAIN QUERY PLAN עובד על פני שתיהן. אין סבב רשת: שני הקבצים פתוחים באותו תהליך.
זה שימושי באמת להפרדת נתונים חמים מארכיונים קרים, לקבצים נפרדים לכל לקוח, או לשליפת נתוני עזר ממסד נתונים לקריאה בלבד.
צירופים לקריאה בלבד ובזיכרון
אם מסד הנתונים השני הוא משהו שאתם רוצים לקרוא אבל אף פעם לא לשנות, למשל מאגר נתוני עזר שמגיע עם האפליקציה, צרפו אותו לקריאה בלבד עם URI:
צורת ה-URI דורשת שבספריית SQLite יהיה SQLITE_OPEN_URI מופעל (הוא מופעל ב-CLI וברוב הספריות לשפות תכנות). כל INSERT, UPDATE או DELETE על ref.* יזרוק אז שגיאה לפני שייגע בקובץ.
צירופים בזיכרון שימושיים באותה מידה להכנת נתונים ביניים:
scratch נעלם כשהחיבור נסגר. זה כמו temp, אבל אתם שולטים במשך החיים שלו.
טרנזקציות חלות על כל מסד נתונים מצורף
BEGIN/COMMIT אחד מכסה כתיבות ל-main ולכל סכמה מצורפת. או שהכול מתבצע או שהכול מתבטל: האטומיות נשמרת על פני קבצים:
העברת שורות מטבלה חיה לקובץ ארכיון היא בדיוק סוג הפעולה שבה רוצים את ההבטחה הזו. בלי אטומיות בין קבצים, קריסה באמצע הייתה משאירה אתכם עם כפילויות, או גרוע מזה, עם שורות שאבדו.
הסתייגות אחת: כשכותבים ליותר ממסד נתונים מצורף אחד בטרנזקציה, SQLite משתמשת בפרוטוקול commit זהיר יותר שדורש journal זמני. זה איטי יותר מ-commit על קובץ יחיד, אבל עדיין בטוח.
ניתוק
כשסיימתם עם מסד נתונים מצורף, הסירו אותו:
DETACH DATABASE archive;
הקובץ נשאר בדיסק בלי שינוי: DETACH רק סוגר את הידית בחיבור הנוכחי. שתי מגבלות שכדאי לזכור:
- אי אפשר לנתק את
mainאו אתtemp. - אי אפשר לנתק מסד נתונים שנמצא כרגע בתוך טרנזקציה או שיש עליו פקודות פתוחות.
אם שכחתם לנתק, זה לא סוף העולם: סגירת החיבור מנקה הכול.
מגבלות ושגיאות נפוצות
כמה מגבלות מעשיות שכדאי להכיר:
- מגבלת ברירת המחדל היא 10 מסדי נתונים מצורפים לכל חיבור (בנוסף ל-
mainו-temp). המקסימום בזמן קומפילציה הוא 125. הגעתם למגבלה? תראוtoo many attached databases - max 10. - כל קובץ מצורף משתמש במטמון דפים. צירוף תריסר מסדי נתונים גדולים לא בא בחינם: צריכת ה-RAM עולה.
- את
ATTACHעצמו אי אפשר להריץ בתוך טרנזקציה. הריצו אותו לפניBEGINאו אחריCOMMIT.
כמה שגיאות שכנראה תפגשו:
-- הקובץ לא קיים ואין הרשאת כתיבה לתיקייה:
Error: unable to open database: 'missing/path.db'
-- ניסיתם לכתוב לצירוף שהוא לקריאה בלבד:
Error: attempt to write a readonly database
-- השתמשתם באותו כינוי פעמיים:
Error: database archive is already in use
רובן ברורות מאליהן ברגע שקוראים אותן. זו של "already in use" מבלבלת אנשים: ATTACH לא מחליף כינוי קיים; צריך לעשות DETACH קודם.
דפוס מציאותי: הפרדה בין חם לקר
כשמחברים הכול יחד, הנה תהליך ארכוב קטן שמעביר הזמנות בנות יותר משנה אל מחוץ למסד הנתונים הראשי:
שורות ישנות עוברות ל-archive.orders, והחדשות נשארות ב-main. דוחות שצריכים היסטוריה יכולים לצרף את שתיהן; שאילתות יומיומיות על main.orders נשארות מהירות כי הטבלה קטנה יותר. אותו חיבור, שני קבצים, טרנזקציה אחת.
הבא בתור: Prepared Statements
ATTACH עוסק במתן גישה לחיבור אחד ליותר נתונים. קבוצת הנושאים הבאה עוסקת באופן שבו אפליקציות מדברות עם SQLite בצורה בטוחה ויעילה, ומתחילה ב-prepared statements, הבסיס לקשירת פרמטרים ולשאילתות חסינות מפני הזרקה.
שאלות נפוצות
מה עושה ATTACH DATABASE ב-SQLite?
ATTACH DATABASE 'file.db' AS alias פותח קובץ מסד נתונים נוסף של SQLite בתוך החיבור הנוכחי ונותן לו שם סכמה. מעכשיו אפשר לפנות לטבלאות שלו כ-alias.table_name ולצרף אותן בשאילתה אחת לטבלאות שבמסד הנתונים הראשי.
כמה מסדי נתונים SQLite יכולה לצרף בבת אחת?
כברירת מחדל, SQLite מאפשרת עד 10 מסדי נתונים מצורפים לכל חיבור, בנוסף לסכמות main ו-temp. התקרה הקשיחה היא 125, וניתנת להגדרה בזמן הקומפילציה דרך SQLITE_MAX_ATTACHED. אם תגיעו למגבלה, תקבלו את השגיאה too many attached databases.
אפשר לתשאל כמה מסדי נתונים מצורפים של SQLite בפקודה אחת?
כן. אחרי הצירוף, הוסיפו לכל טבלה את שם הסכמה שלה: SELECT * FROM main.users JOIN archive.orders ON .... JOIN, תת שאילתות ו-INSERT ... SELECT עובדים כולם בין סכמות. גם טרנזקציות חלות על כל מסד נתונים מצורף, כך ש-COMMIT הוא אטומי על פני כל הקבצים.
איך מנתקים מסד נתונים של SQLite?
הריצו DETACH DATABASE alias. הקובץ נשאר בדיסק בלי שינוי: DETACH רק סוגר את הידית בחיבור הנוכחי. אי אפשר לנתק את main או את temp, ואי אפשר לנתק מסד נתונים שנמצא באמצע טרנזקציה.