מטמון לשאילתות בדאטהבייס

מצ"ב מימוש לקלאס שנכנס להוקים הנכונים על מנת לשמור בתיקיה תחת uploads/cache/queries את השאילתות לדאטהבייס פר צירוף של query vars. דהיינו, לפני שניגש לבצע את השאילתא בודק אם נמצא הקובץ המתאים, במידה ונמצא מחזיר את תוכנו, ובמידה ולא נמצא מבצע את השאילתא ואז שומר את התוצאות באותו הקובץ. כל מה שצריך לעשות הוא רק לאתחל את הקלאס הזה ב- functions.php.

הקלאס מתביית על שלושה הוקים:

  1. posts_pre_query, המקום שבו ניתן להשחיל לשאילתא תוצאות ולמנוע מהתוכנית להזדקק לפניה לדאטהבייס על מנת להניב את התוצאות הללו. התוכנית לוקחת את המערך של משתני הקוורי, עושה לו סריאליזציה ואז האשינג, מאחר שכל מערך כזה הוא יחידאי, סריאלציה והאשינג שלו יהיה גם יחידאי, ולכן אין חשש, כשנצטרך לדלות מידע פר קוורי, נוכל. בהוק אנו בודקים אם קובץ מתאים לשאילתא אכן קיים ואם קיים מחזירים את תוכנה לאחר דה-סריאליציה.
  2. posts_results. במידה והקובץ אינו קיים או במידה ואני מבקש מפורשות לרמוס את התוצאות בעזרת פרמטר בשם override_cache, אנו יוצרים קובץ ושומרים לתוכו את תוכן הקוורי.
  3. save_post – בכל שמירה של פוסט הקאש יתרוקן כולו. למה לא לשמור את זה בעזרת מזהה על פי פוסט ואז למחוק רק את השאילתא של אותו הפוסט? בפשטות, זה בלתי אפשרי. אני רוצה לשלוט בכל שאילתא, ישנם אינספור סוגי שאילתות ואני לא יכול לצפות אותן. לכן אני לא יכול למחוק תוצאות שאילתא ספציפית ואני חייב למחוק את כולן. ברוב המקרים השאילתות גם ככה יהיו מאונדקסות כך שלא נרוויח עד כדי כך הרבה מהקאש, אבל במקרה של שאילתות לא מאונדקסות, כאלה שיקחו 0.3 שניות, אם נפנה לקובץ ונקח את התוצאות המחיר שזה יגבה מאיתנו הוא פחות מ-0.001 שניות וכך הרווחנו 0.3 שניות. הדבר מתבטא בעיקר בסקיילינג גבוה, אך גם באמצעות שאילתות מלאות ב"ג'וינים".
class db_cache {
	protected $folder;

	public function __construct() {
		add_filter( 'posts_pre_query', array( $this, 'posts_pre_query' ), 10, 2 );
		add_filter( 'posts_results', array( $this, 'posts_results' ), 10, 2 );
		add_action( 'save_post', array( $this, 'save_post' ), 10, 3 );

		$this->folder = WP_CONTENT_DIR . "/uploads/cache/queries/";
	}

	public function save_post( $id, $post, $bool ) {
		array_map('unlink', glob("{$this->folder}/*"));
	}

	public function posts_results( $posts, $query ) {
		$md5 = md5( serialize( $query->query_vars ) );
		if ( $md5 && ! is_admin() ) {
			$file      = $md5 . '.txt';
			$full_path = $this->folder . $file;
			if ( ! file_exists( $full_path ) || ( isset( $_GET['override_cache'] ) && $_GET['override_cache'] ) ) {
				$output = serialize( $posts );
				self::create_folders_up_to_path( $full_path );
				$write = file_put_contents( $full_path, $output );
			}
		}

		return $posts;
	}


	public function posts_pre_query( $something, $query ) {
		$md5 = md5( serialize( $query->query_vars ) );
		if ( $md5 ) {
			$file      = $md5 . '.txt';
			$full_path = $this->folder . $file;
			if ( file_exists( $full_path ) && $content = file_get_contents( $full_path ) ) {
				return unserialize( $content );
			}
		}

		return null;
	}

	static public function create_folders_up_to_path( $path ) {
		$pathinfo = pathinfo( $path );
		$unexists = array();
		$checked  = isset( $pathinfo['dirname'] ) ? $pathinfo['dirname'] : false;

		while ( $checked && ! file_exists( $checked ) ) {
			$unexists[] = substr( $checked, strrpos( $checked, '/' ), strlen( $checked ) );
			$checked    = substr( $checked, 0, strrpos( $checked, '/' ) );
		}

		$success = true;
		while ( count( $unexists ) ) {
			$checked = $checked . array_pop( $unexists );
			$success &= mkdir( $checked );
			$checked .= '/';
		}

		return $success;
	}
}
טיפים ומאמרים cache, אופטימיזציה, דאטהבייס, וורדפרס, קאש

בחזרה למאמרים