0

PHP/MySQLアプリケーションの次のコードで問題が発生しました。正常に動作し、約3〜4秒かかりますが、最初の実行(セッションごと)には約2分かかります。自動キャッシュメカニズムがいくつかあるからだと思います。最初の実行を高速化する方法はありますか?このMySQLサーバーにrootアクセス権を持っていますが、DB構造を変更できません。

アプリケーションはここhttp://hotel.crosstourpoint.eu/に表示され、遅いスクリプトはhttp://hotel.crosstourpoint.eu/ajax/html_hotel_details.phpです。チェックアウトするには、メインボックスで何かを検索します。例:「Milano」と入力して[Cerca]をクリックし、[Milano]オプションをクリックして、開始日と終了日( "Giorno di arrivo-Giorno di partenza")を選択し、もう一度[Cerca]をクリックします。情報(I)アイコンは、ajax呼び出しで遅いスクリプトを開きます。

ありがとう。

コード

<?php

// open mysqli connection
$mysqli = new mysqli('localhost', 'hotelbeds', 'import', 'hotelbeds');
if (mysqli_connect_errno()) { printf("Connect failed: %s\n", mysqli_connect_error()); exit(); }

$code   = (int) $_REQUEST['code'];
$h      = array();

// hotel position
$request = '
    SELECT
        NAME, LATITUDE, LONGITUDE
    FROM
        HOTELS
    WHERE
        HOTELCODE = ' . $code . '   ';

$stmt = $mysqli->prepare($request);
$stmt->execute();
$stmt->bind_result( $h['name'], $h['latitude'], $h['longitude'] );
$stmt->fetch();
$stmt->close();
unset($stmt);
unset($request);

// loading descriptions
$request = '
    SELECT
        HotelFacilities, HotelHowToGetThere, HotelComments
    FROM
        HOTEL_DESCRIPTIONS
    WHERE
        HotelCode = ' . $code . '
        AND
        LanguageCode = "' . HB_LANGCODE . '"    '; 

$stmt = $mysqli->prepare($request);
$stmt->execute();
$stmt->bind_result( $h['facilities'], $h['hotelhowtogetthere'], $h['comments'] );
$stmt->fetch();
$stmt->close();
unset($stmt);
unset($request);

// hotel images
$request = '
    SELECT
        IMAGEPATH
    FROM
        HOTEL_IMAGES
    WHERE
        HOTELCODE = ' . $code . '   '; 
$stmt = $mysqli->prepare($request);
$stmt->execute();
$stmt->bind_result( $imagepath );
$images = array();
while( $stmt->fetch() ) array_push( $images, $imagepath );
$stmt->close();
unset($stmt);
unset($request);

テーブル構造

ホテル:約50.000行

HOTELS_DESCRIPTIONS約600.000行

HOTELS_IMAGES:約180.000行

CREATE TABLE `HOTELS` (
  `HOTELCODE` varchar(8) collate utf8_spanish_ci NOT NULL,
  `NAME` varchar(50) collate utf8_spanish_ci NOT NULL,
  `CATEGORYCODE` varchar(5) collate utf8_spanish_ci NOT NULL,
  `DESTINATIONCODE` varchar(3) collate utf8_spanish_ci NOT NULL,
  `ZONECODE` varchar(8) collate utf8_spanish_ci default NULL,
  `CHAINCODE` varchar(5) collate utf8_spanish_ci default NULL,
  `LICENCE` varchar(15) collate utf8_spanish_ci default NULL,
  `LATITUDE` varchar(45) collate utf8_spanish_ci default NULL,
  `LONGITUDE` varchar(45) collate utf8_spanish_ci default NULL,
  PRIMARY KEY  (`HOTELCODE`),
  KEY `HOTELS_CATEGORIES_FK` (`CATEGORYCODE`),
  KEY `HOTELS_ZONES_FK` (`ZONECODE`),
  CONSTRAINT `HOTELS_ZONES_FK` FOREIGN KEY (`ZONECODE`) REFERENCES `ZONES` (`ZONECODE`) ON DELETE CASCADE,
  CONSTRAINT `HOTELS_CATEGORIES_FK` FOREIGN KEY (`CATEGORYCODE`) REFERENCES `CATEGORIES` (`CategoryCode`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci COMMENT='Hotels'

CREATE TABLE `HOTEL_DESCRIPTIONS` (
  `HotelCode` varchar(8) collate utf8_spanish_ci NOT NULL,
  `LanguageCode` varchar(3) collate utf8_spanish_ci NOT NULL,
  `HotelFacilities` varchar(2000) collate utf8_spanish_ci default NULL,
  `HotelLocationDescription` varchar(2000) collate utf8_spanish_ci default NULL,
  `HotelRoomDescription` varchar(2000) collate utf8_spanish_ci default NULL,
  `HolelSportDescription` varchar(2000) collate utf8_spanish_ci default NULL,
  `HotelMealsDescription` varchar(2000) collate utf8_spanish_ci default NULL,
  `HotelPaymentMethods` varchar(2000) collate utf8_spanish_ci default NULL,
  `HotelHowToGetThere` varchar(2000) collate utf8_spanish_ci default NULL,
  `HotelComments` varchar(2000) collate utf8_spanish_ci default NULL,
  PRIMARY KEY  (`HotelCode`,`LanguageCode`),
  KEY `HOTEL_DESCRIPTIOS_LANGUAGES_FK` (`LanguageCode`),
  CONSTRAINT `HOTEL_DESCRIPTIOS_LANGUAGES_FK` FOREIGN KEY (`LanguageCode`) REFERENCES `LANGUAGES` (`LANGUAGECODE`) ON DELETE CASCADE,
  CONSTRAINT `HOTEL_DESCRIPTIOS_HOTELS_FK` FOREIGN KEY (`HotelCode`) REFERENCES `HOTELS` (`HOTELCODE`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci COMMENT='Hotel_Descriptions'

CREATE TABLE `HOTEL_IMAGES` (
  `HOTELCODE` varchar(8) collate utf8_spanish_ci NOT NULL,
  `IMAGECODE` varchar(3) collate utf8_spanish_ci NOT NULL,
  `ORDER_` varchar(5) collate utf8_spanish_ci NOT NULL,
  `VISUALIZATIONORDER` varchar(5) collate utf8_spanish_ci default NULL,
  `IMAGEPATH` varchar(2000) collate utf8_spanish_ci NOT NULL,
  PRIMARY KEY  (`HOTELCODE`,`IMAGECODE`,`ORDER_`),
  KEY `HOTEL_IMAGES_IMAGE_TYPES_FK` (`IMAGECODE`),
  CONSTRAINT `HOTEL_IMAGES_IMAGE_TYPES_FK` FOREIGN KEY (`IMAGECODE`) REFERENCES `IMAGE_TYPES` (`IMAGECODE`) ON DELETE CASCADE,
  CONSTRAINT `HOTEL_IMAGES_HOTELS_FK` FOREIGN KEY (`HOTELCODE`) REFERENCES `HOTELS` (`HOTELCODE`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci COMMENT='Hotels_Images'

追加情報(編集):

Ubuntu64ビット8.04.2Linuxホスト名

2.6.24-23-サーバー#1 SMP Wed Apr 1 22:14:30 UTC 2009 x86_64 GNU / Linux

mysql Ver 14.12 Distrib 5.0.51a、readline 5.2を使用したdebian-linux-gnu(x86_64)用

innodb_buffer_pool_size 512

説明:

>> EXPLAIN SELECT NAME, LATITUDE, LONGITUDE  FROM HOTELS WHERE HOTELCODE = 136224
id | select_type | table | type | possibile_keys | key key_len | ref | rows
1 SIMPLE HOTELS ALL PRIMARY 47373 Using where

>> EXPLAIN  SELECT HotelFacilities, HotelHowToGetThere, HotelComments FROM   HOTEL_DESCRIPTIONS WHERE HotelCode = 136224 AND LanguageCode = "ITA"
id | select_type | table | type | possibile_keys | key key_len | ref | rows
1 SIMPLE HOTEL_DESCRIPTIONS ref PRIMARY,HOTEL_DESCRIPTIOS_LANGUAGES_FK HOTEL_DESCRIPTIOS_LANGUAGES_FK 11 const 75378 Using where

>> EXPLAIN SELECT IMAGEPATH FROM HOTEL_IMAGES WHERE HOTELCODE = 136224
id | select_type | table | type | possibile_keys | key key_len | ref | rows
1 SIMPLE HOTEL_IMAGES ALL PRIMARY 158786    Using where
4

3 に答える 3

2

DB構造を変更することはできないとおっしゃっていますが、これは最も残念なことです。ほとんどの場合、DB構造に関するアドバイスがあります...

クエリに参加するクエリ
は、取得するのとほぼ同じくらいタイトです。

これらすべてを次のような1つの大きなクエリにまとめることができます。

$request = 'SELECT         
  h.NAME, h.LATITUDE, h.LONGITUDE
  ,hd.HotelFacilities, hd.HotelHowToGetThere, hd.HotelComments
  ,hi.ImagePath
FROM HOTELS 
INNER JOIN HOTEL_DESCRIPTIONS hd ON (h.Hotelcode = hd.Hotelcode)
INNER JOIN HOTEL_IMAGES hi ON (h.Hotelcode = hi.Hotelcode)
WHERE HD.Hotelcode = "' .$code. '" AND HD.LanguageCode = "' . HB_LANGCODE . '"  ';

キャッシュを最適化する
これにより、より多くのキャッシュがクエリキャッシュに収まるようになります。
最初のクエリの遅延は、コールドクエリキャッシュが原因で発生します。 詳細については、 http
://www.mysqlperformanceblog.com/2006/07/27/mysql-query-cache/を参照してください。(記事には、これはもはや真実ではないと記載されていることに注意してください。5.1.17以降、プリペアドステートメントはキャッシュされます。)
prepared statements are not cached

テーブル構造に関するいくつかの提案

主キー
フィールドをhotelcode整数にします。テーブルホテルのみの自動インクリメントにします。Hotelcodeはintです(:を参照$code = (int) $_REQUEST['code'];
では、なぜそれをvarcharにするのですか?

varcharではなくxの小さな値にはchar(x)を
使用します。varchar(3)は使用せず、char(3)を使用します。varchar(3)は可変長であり、文字列の長さを計算するために余分な処理時間がかかります。3文字しかないため、実際のスペースを節約できません。x <8の場合はchar(x)を使用することをお勧めします。

外部キー
外部キーには整数のみを使用してみてください。外部キーはより高速に動作し、外部キーは通常、他のテーブルの主キー(PK)にリンクされます。これはとにかく整数である必要があります(上記のポイントを参照)。

InnoDBと主キー
InnoDBでは、主キーはすべてのインデックスに関連付けられているため、主キーを短くすると、挿入、更新、選択のたびに高速化されます。
差出人: http: //dev.mysql.com/doc/refman/5.0/en/innodb-physical-record.html

各セカンダリインデックスレコードには、セカンダリインデックスにないクラスター化インデックスキーに対して定義されたすべてのプライマリキーフィールドも含まれます。これらの主キーフィールドのいずれかが可変長である場合、2次索引が固定長列で定義されている場合でも、各2次索引のレコード・ヘッダーには、それらの長さを記録するための可変長部分があります。

PKは複合キーであってはなりません
複合主キーを持つテーブルの場合、それを強制終了し、自動インクリメント整数主キー(名前付きidまたはそのようなもの)に置き換えます。これは、innoDBがPKのコピーをすべてのインデックスB +ツリーに格納するためです(上記のポイントを参照)。
現在の主キーを一意のキーに置き換えて、同じ言語などで2つの説明がホテルにないことを確認します。

于 2011-05-05T13:19:02.403 に答える
1

Johanはクエリの調整についていくつかの良いアドバイスを提供しましたが、私のコメントによると、これは「最初の実行(セッションごと)に約2分かかる」理由とは関係ありません。これらの手段がなくても、クエリはほんの一瞬で済むはずです。そして、あなたが示したコードには、遅い動作が「最初の実行(セッションごと)」に固有である理由を説明するものは何もありません。

遅いクエリログには何が表示されますか?

私は通常、ここに投稿されたコードから不要なものを切り取ってくれたことに感謝していますが、この場合、実際に速度低下を引き起こしているものはすべて切り取ったと思います。

速度が遅いのは、セッションごとの最初の実行に固有であると思われる理由は何ですか?

問題を見つけるには、スクリプト内の残りのコードをプロファイリングする必要があると思います。

于 2011-05-05T13:29:25.620 に答える
0

回避策を提案します
。セッションが開始されるとすぐに、データベースをウェイクアップするために、任意の$ code値で同じクエリを実行するajaxリクエストを実行します。これにより、ユーザーがクエリの必要性に到達したときに、実行に3〜4秒

于 2011-05-05T13:18:29.967 に答える