Wolne wczytywanie podstrony pobieranej poprzez jQuery

0

Witam,
rozmawiałem ze znajomym który tworząc swoją stronę wykonuje około 10 zapytań (pobiera zdjęcie, info o przyciskach typu "lubie to" itp.). Pokazywał mi działanie i powiem, że zachrzania (wszystko w ułamek sekundy). Napisałem więc co takiego:

Klasa która łączy się z bazą danych poprzez driver MySQLi w ten sposób:

<?php
class MySQL
{
  protected $dbResult = false;

	/*
		$query - zapytanie
		$isErrorDisplayed - czy błąd ma być wyświetlany (default: false)
	*/
	function __construct($query, $isErrorDisplayed = false)
	{
		$conn = new mysqli('host', 'user', 'pass', 'database');		// połączenie z bazą danych

		if(!@$conn->connect_error)						// jeżeli połączenie jest udane
		{
		    @$conn->set_charset($charset);					// ustawiam kodowanie dla pobieranych danych
		    //@$conn->query("SET NAMES {$charset}");			// ustawiam kodowanie dla pobieranych danych
		    $this->dbResult = @$conn->query($query);		// wysyłam zapytanie i pobieram wynik (w tym ilość rekordów i pól)

		    if($conn->error && $isErrorDisplayed)		// wyświetla błąd zapytania (w zależności od $isErrorDisplayed)
		    {
		    	exit($conn->error);
		    }

		} elseif ($isErrorDisplayed) {					// wyświetla błąd połączenia (w zależności od $isErrorDisplayed)
			exit($conn->connect_error);
		}
	}
	
	/* Funkcja zwraca wynik zapytania */
	public function response()
	{
		return $this->dbResult;
	}
}
?>

Pobranie 20 zdjęć (oddzielne zapytania):

<?php
include_once("class.MySQL.php");

for($i=1; $i<=20; $i++)
{
$img = new MySQL("SELECT image FROM dbImages WHERE `id` = '{$i}'");
// na razie pomijam wyświetlanie bo ono nie ma znaczącego wpływu na prędkość wczytywania
}
?>

Strona wczytuje się w 15 sekund... Gdy zmienię kod na taki:

<?php
include_once("class.MySQL.php");

$nr = array();
for($i=1; $i<=20; $i++) { array_push($nr, $i); }

$ids = implode("','", $nr);
$img = new MySQL("SELECT image FROM dbImages WHERE `id` IN('{$ids}')'");
// na razie pomijam wyświetlanie bo ono nie ma znaczącego wpływu na prędkość wczytywania
}
?>

Strona wczytuje się w niecałe 2 sekundy. Z czym to jest związane? Z moim serwerem (używam WebServ)? Z tym, że musiał mi ściemniać w tym co mówił, albo jego kod wysyła jedno "zgrupowane" zapytanie do bazy? Z tego co wiem on wszystko ma na Amazonie.

Proszę o poradę, ponieważ obecnie muszę przerabiać całą stronę, ponieważ wszystko jest oparte na założeniu, że z początku postu (mój błąd). Proszę też o poradę jaki serwer/framework/metodę działania wybrać, aby było wszystko ok.

1

Zacznijmy może od tego, że za samo tworzenie osobnej instancji MySQLi na każde zapytanie ten wątek powinien trafić do perełek, a Ty powinieneś dostać batem po tyłku.

Proszę też o poradę jaki serwer/framework/metodę działania wybrać, aby było wszystko ok.
Yii/Zend/CakePHP, wszystko, bylebyś nie pisał własnego frameworka nie mając o tym pojęcia :v

Btw, komentarze stawiaj przed linijką, a nie w tej samej.

0

No dobra, zjebka jest xD A co z resztą?

Co do frameworka to chodzi mi o to, czy jak użyję jakiegoś to ten przykład wykona się szybciej (czyli nie będzie mojego kodu do połączenia z bazą danych)?

Czy masz jakiś przykład poprawnego tworzenia klasy mysql/mysqli? Czy użycie jej spowoduje przyspieszenie pracy programu? Czy jednak to też kwestia serwera?

1

Ja bym zastosował PDO

// $array - lista otrzymanych id
$conn = new PDO('mysql:host=host;dbname=database', 'user', 'pass');
$pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo -> prepare ("SELECT image FROM dbImages WHERE `id` IN(:nr1, :nr2, ... :nr20)");

$stmt -> bindValue(':nr1', $array[0], PDO::PARAM_INT);
...
$stmt -> bindValue(':nr20', $array[19], PDO::PARAM_INT);
$stmt -> execute();
$results = $stmt -> fetch();

return $results;
0

Czy masz jakiś przykład poprawnego tworzenia klasy mysql/mysqli? Czy użycie jej spowoduje przyspieszenie pracy programu? Czy jednak to też kwestia serwera?

$mysql = new MySQL(...);

$result1 = $mysql->query('select cośtam');
$result2 = $mysql->query('select cośtam_innego');
...

Czyli tworzysz raz i wykorzystujesz do wszystkich potrzebnych zapytań.

Frameworki przeważnie mają dodatkowo jakieś buildery w stylu:

$result1 = App::buildQuery()->select('cośtam')->from('tabela')->execute();

Oraz różnej maści cache, więc może to wyglądać na przykład tak:

$images = SqlCache::fetch('images');

if ($images === null) {
  $result = $mysql->query('select cośtam');
  /* tutaj magia, stworzenie tablicy $images */
  SqlCache::save('images', $images);
}

I wtedy mamy zapisaną listę naszych obrazków do pamięci podręcznej, przez co zapytanie wykonane zostaje przypuśćmy raz na dzień, na tydzień. Chyba że są to obrazki, które są często zmieniane - wtedy nie warto bawić się w cache :P

0

Rozumiem, swój błąd - dzięki :)

Mimo wszystko nasuwa mi się trochę pytań. Może zacznę od tego co robię. Piszę "mały" sklep internetowy - nie do sprzedaży, ani do konkretnej pracy tylko dla nauki - w którym (po słowach tego kolegi) przyjąłem taką strategię:

  1. Wchodząc na stronę jakiejś kategorii (np.: Owoce) pobieram produkty w tej kategorii.
  2. Zakładając, że pobrałem 20 produktów na stronę, a każdy z nich ma 5 zdjęć wykonałem to w ten sposób:
    a) SELECT * FROM dbProdukty WHERE id IN (tutaj_numery_id)
    b) wykonuję pętlę po wszystkich produktach tworząc obiekt dla każdego z nich
    c) w klasie Produkt pobieram z bazy zdjęcia dla danego produktu

Czyli wykonuję 21 zapytań do bazy. W takim razie mam dwie metody na przyspieszenie tego działania:

  • pobranie od razu wszystkich produktów i ich zdjęć z bazy i przetworzenie całości dopiero po otrzymaniu
  • utworzenie jednej instancji (wzorzec Singleton), która raz się łączy i pobiera wynik poprzez każdorazowe wywołanie query() - przykład kodu poniżej (pisałem z głowy - kod nietestowany):
<?php
class MySQL
{
  private static $instance = NULL;
  private $conn;
  
	/*
		$query - zapytanie
		$isErrorDisplayed - czy błąd ma być wyświetlany (default: false)
	*/
	function __construct()
	{
		if(empty(self::$instance))
		{
			$this->$conn = new mysqli('host', 'user', 'pass', 'database');		// połączenie z bazą danych
			if(!@$this->conn->connect_error)									// jeżeli połączenie jest udane
			{
				@$this->conn->set_charset('utf8');					// ustawiam kodowanie dla pobieranych danych
				//$this->conn->query("SET NAMES utf8");				// ustawiam kodowanie dla pobieranych danych
				self::$instance = $this;							// instancja
			} else {
				exit($conn->connect_error);							// wyświetla błąd połączenia
			}
			
		} else {
			$this = self::$instance;
		}
	}
	
	public function query()
	{
		// wyświetla błąd zapytania
		if($this->conn->error) exit($this->conn->error);
		
		// wysyłam zapytanie i pobieram wynik (w tym ilość rekordów i pól)
		return @$conn->query($query);
	}

	public function __destruct()
	{
		$this->$conn->close();
		// lub mysqli_close($this->$conn);
	}
?>
  • Pytanie tylko o ile przyspieszy mi pracę jedno połączenie z bazą i tylko wysyłanie zapytań co jakiś czas?
  • I jeszcze jedno. Mam pliki językowe związane ze stroną i z opisem zdjęć - czy wszystko trzymać w bazie danych, czy część odpowiedzialną za tłumaczenie strona na serwerze, a w bazie danych opisy zdjęć?

1 użytkowników online, w tym zalogowanych: 0, gości: 1