PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אני מציע לך לקרוא את תמליל הדו"ח של ולדימיר סיטניקוב מתחילת 2016, "PostgreSQL ו-JDBC: סחיטת כל המרכיבים"

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

שלום! שמי ולדימיר סיטניקוב. אני עובד ב-NetCracker כבר 10 שנים. ואני עוסק בעיקר בביצועים. כל מה שקשור לג'אווה, כל מה שקשור ל-SQL - זה מה שאני אוהב.

והיום אספר לכם על מה שנתקלנו בו בחברה כשהתחלנו להשתמש ב-PostgreSQL כשרת מסד נתונים. ואנחנו עובדים בעיקר עם ג'אווה. אבל מה שאספר לכם היום לא קשור רק לג'אווה. כפי שהראת התרגול, זה קורה גם בשפות אחרות.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

נדבר:

  • לגבי דגימת נתונים.
  • לגבי שמירת נתונים.
  • וגם לגבי פרודוקטיביות.
  • ולגבי המגרפות התת-ימיות שקבורות שם.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

נתחיל עם שאלה פשוטה. אנו בוחרים שורה אחת מטבלה לפי מפתח ראשי.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

מסד הנתונים נמצא על אותו מחשב. וכל הדברים האלה לוקחים 20 מילישניות.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

20 מילישניות אלו הן המון. אם יש לך 100 בקשות כאלה, אז אתה מבזבז זמן בכל שנייה כדי לגלול בין הבקשות הללו, כלומר אנחנו מבזבזים זמן.

אנחנו לא אוהבים לעשות את זה ואנחנו בוחנים מה מסד הנתונים מציע לנו לשם כך. מסד הנתונים מציע לנו שתי אפשרויות לביצוע שאילתות.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

האפשרות הראשונה היא בקשה פשוטה. מה טוב בה? כי אנחנו מקבלים אותה ושולחים אותה, ולא יותר מזה.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

https://github.com/pgjdbc/pgjdbc/pull/478

למסד הנתונים יש גם שאילתה מורחבת, שהיא מתוחכמת יותר אך פונקציונלית יותר. ניתן לשלוח שאילתה בנפרד לצורך ניתוח, ביצוע, קשירת משתנים וכו'.

שאילתה מורחבת במיוחד היא משהו שלא נסקור בדוח הנוכחי. ייתכן שנרצה משהו מהבסיס ויש רשימת משאלות שנוצרה בצורה כלשהי, כלומר זה מה שאנחנו רוצים, אבל זה בלתי אפשרי עכשיו ובשנה הקרובה. לכן, פשוט רשמנו את זה ונסתובב וננער את האנשים העיקריים.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

ומה שאנחנו יכולים לעשות זה שאילתה פשוטה ושאילתה מורחבת.

מה מיוחד בכל גישה?

שאילתה פשוטה טובה לביצוע חד פעמי. הפעילו אותה פעם אחת ושכחו ממנה. והבעיה היא שהיא לא תומכת בפורמט נתונים בינארי, כלומר היא לא מתאימה למערכות בעלות ביצועים גבוהים.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

שאילתה מורחבת – מאפשרת לך לחסוך זמן בניתוח. זה מה שעשינו והתחלנו להשתמש בו. זה עזר לנו מאוד. יש לא רק חיסכון בניתוח. יש חיסכון בהעברת נתונים. העברת נתונים בפורמט בינארי יעילה הרבה יותר.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

בואו נעבור לתרגול. כך נראית אפליקציה טיפוסית. זה יכול להיות ג'אווה וכו'.

יצרנו משפט. ביצענו פקודה. יצרנו סגירה. איפה השגיאה כאן? מה הבעיה? אין בעיה. כך זה כתוב בכל הספרים. כך זה צריך להיות כתוב. אם אתם רוצים ביצועים מקסימליים, כתבו כך.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אבל התרגול הראה שזה לא עובד. למה? כי יש לנו שיטה שנקראת "close". וכשאנחנו עושים את זה, מנקודת מבט של מסד נתונים מתברר - זה כמו מעשן שעובד עם מסד נתונים. אמרנו "PARSE EXECUTE DEALLOCATE".

למה כל כך הרבה יצירות ופריקות של משפטים? אף אחד לא צריך אותם. אבל בדרך כלל ב-PreparedStatement קורה שכאשר אנחנו סוגרים אותם, הם סוגרים הכל במסד הנתונים. זה לא מה שאנחנו רוצים.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אנחנו רוצים לעבוד עם מסד הנתונים כמו אנשים בריאים. אנחנו לוקחים ומכינים את המשפט שלנו פעם אחת, ואז מבצעים אותו פעמים רבות. למעשה, פעמים רבות פירוש הדבר שאנחנו מנתחים אותו פעם אחת בכל חיי האפליקציה. ואנחנו משתמשים באותו מזהה משפט על מערכות REST שונות. זוהי המטרה שלנו.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

כיצד נוכל להשיג זאת?

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

זה מאוד פשוט - אין צורך לסגור פקודות. אנחנו כותבים כך: "להכין" "לבצע".

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אם נפעיל משהו כזה, ברור שמשהו יעלה על גדותיו איפשהו. אם זה לא ברור, נוכל למדוד את זה. בואו ניקח ונכתוב מדד ביצועים, שבו שיטה פשוטה כזו. אנחנו יוצרים משפט. אנחנו מפעילים אותו על גרסה כלשהי של הדרייבר ומגלים שהוא קורס די מהר עם אובדן כל הזיכרון שיש לנו.

ברור ששגיאות כאלה מתוקנות בקלות. אני לא אדבר עליהן. אבל אני אגיד שבגרסה החדשה זה עובד הרבה יותר מהר. השיטה טיפשית, אבל בכל זאת.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

איך לעבוד נכון? מה אנחנו צריכים לעשות בשביל זה?

במציאות, יישומים תמיד סוגרים פקודות. כל הספרים אומרים לסגור אותן, אחרת הזיכרון ידלוף.

ו-PostgreSQL לא יכול לשמור שאילתות במטמון. כל סשן צריך ליצור את המטמון הזה לעצמו.

ואנחנו גם לא רוצים לבזבז זמן על ניתוח.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

וכרגיל יש לנו שתי אפשרויות.

האפשרות הראשונה היא שאנחנו אומרים, בואו נעטוף הכל ב-PgSQL. יש שם מטמון. הוא שומר הכל במטמון. זה יעבוד מצוין. בדקנו את זה. יש לנו 100500 שאילתות. זה לא עובד. אנחנו לא מסכימים להפוך שאילתות ידנית לפרוצדורות. לא, לא.

יש לנו אפשרות שנייה - לקחת ולנסר את זה בעצמנו. אנחנו פותחים את קוד המקור, מתחילים לנסר. ניסרנו וניסרנו. התברר שזה לא כל כך קשה לעשות.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

https://github.com/pgjdbc/pgjdbc/pull/319

זה הופיע באוגוסט 2015. עכשיו זו גרסה מודרנית יותר. והכל נהדר. זה עובד כל כך טוב שאנחנו לא משנים כלום באפליקציה. ואפילו הפסקנו לחשוב על PgSQL, כלומר זה הספיק לנו כדי להפחית את כל עלויות התקורה כמעט לאפס.

בהתאם לכך, פקודות שהוכנו על ידי השרת מופעלות בביצוע החמישי על מנת לא לבזבז זיכרון במסד הנתונים עבור כל בקשה חד פעמית.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

האם אוכל לשאול - איפה המספרים? מה מקבלים? וכאן לא אתן את המספרים, כי לכל בקשה יש את שלה.

היו לנו שאילתות כאלה שהשקענו בערך 20 מילישניות בניתוח שאילתות OLTP. היו 0,5 מילישניות לביצוע, 20 מילישניות לניתוח. השאילתה היא 10 KiB של טקסט, 170 שורות של התוכנית. זוהי שאילתת OLTP. היא מבקשת 1, 5, 10 שורות, לפעמים יותר.

אבל לא רצינו לבזבז 20 מילישניות בכלל. הפחתנו את זה ל-0. הכל נהדר.

מה אפשר ללמוד מזה? אם יש לך ג'אווה, אז אתה יכול לקחת גרסה מודרנית של הדרייבר וליהנות.

אם יש לכם שפה אחרת, אז תחשבו על זה - אולי אתם צריכים גם את זה? כי מנקודת המבט של השפה הסופית, למשל, אם יש לכם PL 8 או LibPQ, אז לא ברור לכם שאתם מבזבזים זמן לא על ביצוע, אלא על ניתוח וזה שווה בדיקה. איך? הכל בחינם.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

חוץ מזה שיש שגיאות, כמה מוזרויות. ועליהן נדבר עכשיו. רוב זה יעסוק בארכיאולוגיה תעשייתית, במה שמצאנו, במה שנתקלנו.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אם השאילתה נוצרת באופן דינמי. זה קורה. מישהו מדביק מחרוזות יחד, והתוצאה היא שאילתת SQL.

מה לא בסדר בזה? זה לא בסדר כי כל פעם אנחנו מקבלים מחרוזת אחרת.

ויש לחשב מחדש את קוד ה-hashCode של המחרוזת השונה הזו. זוהי באמת משימת CPU - מציאת טקסט שאילתה ארוך אפילו ב-hash קיים אינה כל כך קלה. אז המסקנה פשוטה - אל תיצרו שאילתות. אחסו אותן במשתנה אחד. ותהיו מאושרים.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

הבעיה הבאה. סוגי נתונים הם חשובים. ישנם ORMs שאומרים שלא משנה מהו NULL, שיהיה any. אם הוא Int, אז נאמר setInt. ואם הוא NULL, אז שיהיה תמיד VARCHAR. ומה זה משנה מהו NULL? מסד הנתונים יבין את זה בעצמו. והתמונה הזו לא עובדת.

בפועל, למסד הנתונים כן אכפת. אם בפעם הראשונה אמרת שזה מספר, ובפעם השנייה שזה VARCHAR, אז אי אפשר לעשות שימוש חוזר בפקודות שהוכנו על ידי השרת. ובמקרה הזה, עלינו ליצור מחדש את הפקודה שלנו.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אם אתם מפעילים את אותה שאילתה, ודאו שסוגי הנתונים בעמודה אינם מעורבבים. עליכם להיזהר מ-NULL. זוהי טעות נפוצה שהייתה לנו לאחר שהתחלנו להשתמש ב-PreparedStatements.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אוקיי, הפעלנו את זה. לקחנו, אולי, נהג. והביצועים ירדו. הכל נהיה גרוע.

איך זה קורה? האם זה באג או פיצ'ר? לרוע המזל, לא הצלחנו להבין אם זה באג או פיצ'ר. אבל יש תרחיש פשוט מאוד לשחזור הבעיה הזו. היא ארבה לנו באופן בלתי צפוי לחלוטין. וזה מורכב מבחירה פשוטה מטבלה אחת. כמובן, היו לנו עוד שאילתות כאלה. בדרך כלל הן כללו שתיים או שלוש טבלאות, אבל יש תרחיש כזה לשחזור. קח כל גרסה של מסד הנתונים שלך ושחזר אותה.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

https://gist.github.com/vlsi/df08cbef370b2e86a5c1

העניין הוא שיש לנו שתי עמודות, כל אחת מאונדקסת. בעמודה אחת, יש מיליון שורות לפי ערך NULL. ובעמודה השנייה, יש רק 20 שורות. כאשר אנו מבצעים את הפעולה ללא משתנים מקושרים, הכל עובד כשורה.

אם נתחיל לבצע עם משתנים כבולים, כלומר נריץ את הסימן "?" או "$1" עבור השאילתה שלנו, מה נקבל בסופו של דבר?

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

https://gist.github.com/vlsi/df08cbef370b2e86a5c1

הביצוע הראשון הוא כצפוי. השני קצת יותר מהיר. משהו שמור במטמון. השלישי-רביעי-חמישי. ואז בום - ומשהו כזה. והדבר הכי גרוע הוא שזה קורה בביצוע השישי. מי ידע שצריך לעשות בדיוק שש הוצאות להורג כדי להבין מהי תוכנית הביצוע האמיתית?

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

מי אשם? מה קרה? מסד הנתונים מכיל אופטימיזציה. והוא מותאם למקרה הגנרי. ובהתאם, החל מרגע מסוים הוא עובר לתוכנית הגנרית, שלמרבה הצער עשויה להיות שונה. היא עשויה להיות זהה, או שהיא עשויה להיות שונה. ויש ערך סף כלשהו שמוביל להתנהגות כזו.

מה אפשר לעשות עם זה? כאן, כמובן, קשה יותר להניח משהו. יש פתרון פשוט שאנחנו משתמשים בו. הוא +0, OFFSET 0. בוודאי אתם מכירים פתרונות כאלה. אנחנו פשוט לוקחים ומוסיפים "+0" לבקשה והכל בסדר. אני אראה לכם אחר כך.

ויש עוד אפשרות - לבחון את התוכניות ביתר קפידה. היזם חייב לא רק לכתוב את הבקשה, אלא גם לומר "הסבר נתח" 6 פעמים. אם 5, אז זה לא יעבוד.

וישנה אפשרות שלישית - לכתוב מכתב ל-pgsql-hackers. כתבתי, למרות שעדיין לא ברור אם מדובר בבאג או בתכונה.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

https://gist.github.com/vlsi/df08cbef370b2e86a5c1

בזמן שאנחנו חושבים האם זה באג או פיצ'ר, בואו נתקן את זה. בואו ניקח את השאילתה שלנו ונוסיף "+0". הכל בסדר. שני סמלים ואתם אפילו לא צריכים לחשוב איך ומה יש שם. זה מאוד פשוט. פשוט אסרנו על מסד הנתונים להשתמש באינדקס על העמודה הזו. אין לנו אינדקס על העמודה "+0" וזהו, מסד הנתונים לא משתמש באינדקס, הכל בסדר.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

זהו כלל 6 הסברים. עכשיו, בגרסאות הנוכחיות, צריך לעשות זאת 6 פעמים אם יש משתנים כבולים. אם אין משתנים כבולים, אז נעשה זאת כך. ובסוף, זוהי הבקשה שקורסת. זה לא כל כך מסובך.

נראה, כמה זה אפשרי? באג פה, באג שם. באמת יש באג בכל מקום.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

בואו נסתכל שוב. לדוגמה, יש לנו שתי סכמות. סכמה א' עם טבלה Y וסכמה ב' עם טבלה Y. השאילתה היא לבחור נתונים מהטבלה. מה יהיה לנו? תהיה לנו שגיאה. יהיו לנו את כל האפשרויות הנ"ל. הכלל הוא - אם באג נמצא בכל מקום, יהיו לנו את כל האפשרויות הנ"ל.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

עכשיו השאלה היא: "למה?" נראה שיש תיעוד שאם יש לנו סכימה, אז יש משתנה "search_path" שאומר לנו היכן לחפש את הטבלה. נראה שהמשתנה קיים.

מה הבעיה? הבעיה היא שפקודות שהוכנו על ידי השרת אינן חושדות ש-search_path יכול להשתנות על ידי מישהו. ערך זה נשאר קבוע עבור מסד הנתונים. וחלקים מסוימים עשויים לא לקלוט ערכים חדשים.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

כמובן, זה תלוי בגרסה עליה אתה בודק. זה תלוי עד כמה הטבלאות שלך שונות באופן משמעותי. וגרסה 9.1 פשוט תריץ את השאילתות הישנות. גרסאות חדשות יותר עשויות לזהות את התקלה ולומר לך שיש לך באג.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

הגדר search_path + פקודות שהוכנו על ידי השרת =
אסור לשנות את סוג התוצאה בתוכנית המאוחסנת במטמון

איך לטפל בזה? יש מתכון פשוט - אל תעשו זאת. אל תשנו את search_path באפליקציה. אם תשנו אותו, עדיף ליצור חיבור חדש.

אנחנו יכולים לדון בזה, כלומר לפתוח את זה, לדון בזה, להוסיף עוד קצת. אולי נוכל לשכנע את מפתחי מסד הנתונים שכאשר מישהו משנה ערך, מסד הנתונים צריך לומר ללקוח: "תראה, יש לך ערך מעודכן כאן. אולי אתה צריך לאפס את ההצהרות, ליצור אותן מחדש?". עכשיו מסד הנתונים מתנהג בסתר ולא מדווח בשום צורה שאיפשהו בתוך ההצהרות השתנה.

ואני אדגיש שוב - זה משהו שאינו אופייני לג'אווה. נראה את אותו הדבר ב-PL/pgSQL אחד לאחד. אבל זה ישוחזר שם.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

בואו ננסה שוב לבחור נתונים. אנחנו בוחרים ובוחרים. יש לנו טבלה עם מיליון שורות. כל שורה היא קילובייט. בערך ג'יגה-בייט של נתונים. ויש לנו זיכרון עבודה במכונת ג'אווה של 128 מגה-בייט.

אנחנו, כפי שמומלץ בכל הספרים, משתמשים בעיבוד זרמים. כלומר, אנחנו פותחים את resultSet וקוראים נתונים משם לאט לאט. האם זה יעבוד? האם זה לא ייפול בזיכרון? האם זה ייקרא לאט לאט? בואו נאמין במסד הנתונים, בואו נאמין ב-Postgres. אנחנו לא מאמינים. האם OutOfMemory ייפול? למי OutOfMemory נפל? ומי הצליח לתקן את זה אחרי זה? מישהו הצליח לתקן את זה.

אם יש לך מיליון שורות, אתה לא יכול פשוט לבחור. אתה בהחלט צריך OFFSET/LIMIT. מי בעד האפשרות הזו? ומי בעד האפשרות שאתה צריך כדי לשחק עם autoCommit?

כאן, כרגיל, האפשרות הכי לא צפויה מתגלה כנכונה. ואם פתאום תכבה את autoCommit, זה יעזור. למה? המדע לא יודע על זה.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אבל כברירת מחדל, כל הלקוחות שמתחברים למסד נתונים של Postgres מאחזרים את כל הנתונים. PgJDBC אינו יוצא מן הכלל, והוא מאחזר את כל השורות.

יש וריאציה על ערכת הנושא FetchSize, כלומר ניתן לומר ברמת משפט נפרד שכאן, בבקשה, בחר נתונים לפי 10, 50. אבל זה לא עובד עד שמכבים את autoCommit. כבה את autoCommit - זה מתחיל לעבוד.

אבל לעבור על הקוד ולקבוע setFetchSize בכל מקום זה לא נוח. לכן יצרנו הגדרה שתגיד את ערך ברירת המחדל עבור כל החיבור.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אז אמרנו את זה. הגדרנו את הפרמטר. ומה קיבלנו? אם נבחר קטן, אם, למשל, נבחר 10 שורות, אז יש לנו עלויות תקורה גדולות מאוד. לכן, אנחנו צריכים להגדיר את הערך הזה לכמאה.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

באופן אידיאלי, כמובן, עדיין נצטרך ללמוד להגביל את זה בבתים, אבל המתכון הוא זה: הגדירו את defaultRowFetchSize ליותר ממאה ותיהנו.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

בואו נעבור להכנסת נתונים. הכנסתם פשוטה יותר, ישנן אפשרויות שונות. לדוגמה, INSERT, VALUES. זוהי אפשרות טובה. אפשר לומר "INSERT SELECT". בפועל, זה אותו הדבר. אין הבדל בביצועים.

ספרים אומרים שצריך לעשות פקודות Batch, ספרים אומרים שאפשר לעשות פקודות מורכבות יותר עם מספר סוגריים. ול-Postgres יש תכונה נהדרת - אפשר להעתיק, כלומר לעשות את זה מהר יותר.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אם נמדוד את זה, נוכל לגלות שוב כמה תגליות מעניינות. איך אנחנו רוצים שזה יעבוד? אנחנו לא רוצים לנתח ולא לבצע פקודות מיותרות.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

בפועל, TCP לא מאפשר לנו לעשות זאת. אם הלקוח עסוק בשליחת בקשה, אז מסד הנתונים לא קורא את הבקשות בזמן שהוא מנסה לשלוח לנו תשובות. כתוצאה מכך, הלקוח ממתין שהמסד נתונים יקרא את הבקשה, והמסד נתונים ממתין שהלקוח יקרא את התגובה.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

ולכן הלקוח נאלץ לשלוח חבילת סנכרון מעת לעת. אינטראקציות רשת נוספות, אובדן זמן נוסף.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקובוככל שאנחנו מוסיפים אותם יותר, כך המצב מחמיר. המנהל די פסימי ומוסיף אותם לעתים קרובות למדי, בערך פעם ב-200 שורות, תלוי בגודל השורות וכו'.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

https://github.com/pgjdbc/pgjdbc/pull/380

קורה שמתקנים רק שורה אחת והכל מאיץ פי 10. זה קורה. למה? כרגיל, הקבוע כבר היה בשימוש איפשהו. והערך "128" אומר - אל תשתמשו בעיבוד קבוצות (batching).

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

רתמת מיקרו-בנצ'מרק של ג'אווה

מזל שזה לא נכנס לגרסה הרשמית. זה התגלה לפני שהתחילו לשחרר את זה. כל המשמעויות שאני נותן מבוססות על גרסאות מודרניות.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

בואו נמדוד. אנחנו מודדים InsertBatch פשוט. אנחנו מודדים InsertBatch מרובה, כלומר את אותו הדבר, אבל יש הרבה ערכים. מהלך חכם. לא כולם יכולים לעשות את זה, אבל זה מהלך כל כך פשוט, הרבה יותר פשוט מ-COPY.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אתה יכול לעשות העתקה.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

ואתה יכול לעשות זאת על מבנים. להצהיר על סוג ברירת מחדל של משתמש, להעביר מערך ולהוסיף ישירות לטבלה.

אם תפתחו את הקישור: pgjdbc/ubenchmsrk/InsertBatch.java, אז הקוד הזה נמצא ב-GitHub. תוכלו לראות ספציפית אילו שאילתות נוצרות שם. זה לא משנה.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

השקנו את זה. והדבר הראשון שהבנו הוא שאי אפשר להשתמש ב-batch. כל אפשרויות ה-batching הן אפס, כלומר זמן הביצוע הוא כמעט אפס בהשוואה לביצוע בודד.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

אנחנו מכניסים נתונים. זוהי טבלה פשוטה מאוד. שלוש עמודות. ומה אנחנו רואים כאן? אנחנו רואים שכל שלוש האפשרויות דומות פחות או יותר. ו-COPY, כמובן, עדיף.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

זה הזמן שבו אנו מוסיפים חתיכות. כאשר אמרנו שערך VALUES אחד, שני ערכי VALUES, שלושה ערכי VALUES, או שציינו 10 מהם מופרדים בפסיקים. זה עכשיו בדיוק אופקית. 1, 2, 4, 128. ניתן לראות ש-Batch Insert, המצויר בכחול, מקבל הקלה רבה מכך. כלומר, כאשר מוסיפים אחד אחד או אפילו כאשר מוסיפים ארבעה על ארבעה, זה הופך להיות טוב פי שניים, פשוט בגלל שדחפנו קצת יותר לתוך VALUES. פחות פעולות EXECUTE.

שימוש ב-COPY על נפחים קטנים הוא לא מבטיח במיוחד. אפילו לא ציירתי על שני הראשונים. הם עולים לשמיים, כלומר המספרים הירוקים האלה עבור COPY.

יש להשתמש ב-COPY כאשר נפח הנתונים שלכם הוא לפחות יותר ממאה שורות. התקורה של פתיחת חיבור זה גדולה. ולמען האמת, לא חפרתי בכיוון הזה. אופטימיזציתי את Batch, אבל לא את COPY.

מה נעשה הלאה? אנו מודדים. אנו מבינים שעלינו להשתמש או במבנים או בתבנית חכמה המשלבת מספר משמעויות.

PostgreSQL ו-JDBC סוחטים את כל המיץ. ולדימיר סיטניקוב

מה עלינו לקחת מהדיווח של היום?

  • PreparedStatement הוא הכל עבורנו. הוא נותן הרבה עבור ביצועים. הוא נותן חבית גדולה של זפת.
  • ואתה צריך לעשות את הפעולה "הסבר" ו"ניתוח" 6 פעמים.
  • ואנחנו צריכים לדלל את OFFSET 0 עם טריקים כמו +0 כדי לתקן את האחוז הנותר של השאילתות הבעייתיות שלנו.

מקור: www.habr.com

קנה אירוח אמין לאתרים עם הגנת DDoS, שרתי VPS VDS 🔥 קנה אחסון אתרים אמין עם הגנת DDoS, שרתי VPS VDS | ProHoster