1

次のデータベース構造があります。

CREATE TABLE IF NOT EXISTS `business` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `address` varchar(255) NOT NULL,
  `city` varchar(255) NOT NULL,
  `state` varchar(255) NOT NULL,
  `postal` int(11) NOT NULL,
  `country` varchar(255) NOT NULL,
  `lat` float NOT NULL,
  `lng` float NOT NULL,
  `name` varchar(255) NOT NULL,
  `phone` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `website` varchar(255) NOT NULL,
  `userID` bigint(20) NOT NULL,
  `url` varchar(255) NOT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `clicks` bigint(20) NOT NULL,
  `oHours` varchar(255) NOT NULL,
  `featured` tinyint(1) NOT NULL,
  `imageThumb` varchar(255) NOT NULL DEFAULT 'default.jpg',
  `imageOrig` varchar(255) NOT NULL DEFAULT 'default.jpg',
  `flag` tinyint(1) NOT NULL,
  `display` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=589846 ;

このテーブル (ビジネス) には 507,736 件のレコードがあります

CREATE TABLE IF NOT EXISTS `businesscat` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `bizID` bigint(20) NOT NULL,
  `catID` bigint(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=589863 ;

このテーブル (businesscat) には 519,825 件のレコードがあります

CREATE TABLE IF NOT EXISTS `category` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `url` varchar(255) NOT NULL,
  `icon` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;

このテーブル (カテゴリ) には 5 つのレコードしかありません

だから、私の問題は、ffを使用して最も近いビジネスの計算で100レコードを取得しようとしていることです:

SELECT business.name
, business.lng
, business.lat
, business.address
, business.city
, business.state
, business.postal
, business.phone
, business.url
, business.imageThumb
, businesscat.catID
, category.icon
, (((acos(sin((".$lat."*pi()/180)) 
  * sin((business.lat*pi()/180))
  + cos((".$lat."*pi()/180)) 
  * cos((business.lat*pi()/180)) 
  * cos(((".$lng."-business.lng)*pi()/180))))
  * 180/pi())*60*1.1515) AS distance
FROM business 
INNER JOIN businesscat ON businesscat.bizID=business.id 
INNER JOIN category ON category.id=businesscat.catID
ORDER BY distance LIMIT 100 

より速くするためのアイデアはありますか?

4

2 に答える 2

2

サブクエリに ORDER BY と LIMIT を含めることができるという MySQL のマニュアルを読みました。したがって、私の提案は次のようになります。

距離の計算は、ORDER BY 句と LIMIT 句と共に別のサブクエリに入れます。次に、結合を囲んでいる (外側の) クエリに入れます。このようにして、最初から関心のある領域外にある何十万ものビジネスに対して、結合の操作が実行されることはありません。

また、businesscat.bizID および businesscat.catID のインデックスが定義されていることを確認してください。

編集:それでクエリが目的に十分な速度にならない場合は、次のことを試してください。

クエリを入力する前に、「最小」および「最大」の経度と緯度 ($lng と $lat の北、西、東、南に 100 メートル) を計算します。内部クエリは次のとおりですWHERE business.lng >= $min_lng AND business.lng <= $max_lng AND business.lat >= $min_lat AND business.lat <= $max_lat。次に、外側のクエリで距離を計算し、それによって再フィルター処理します。もちろん、これは、business.lng と business.lat にインデックスを定義することで、さらに最適化できます。

于 2011-12-26T12:42:37.067 に答える
0

bigintに保存できるデータの量を知っていますか?宇宙全体にとってはそれで十分でしょう。Smallintまたは多分mediumintが良いです。

All of the fields have varchar(255)! do you really need that much data?

mySQLクエリ実行プランをキャッシュできますが、それを使用しますか?

テーブルのストレージエンジンはInnoDBなので、もっと重要な質問をさせてください。

Do you use innodb_file_per_table setting?

ORDERBYまたはJOINSで使用するすべてのフィールドにインデックスを付けます。

  • 距離はインデックス化されていません
  • UserIDは索引付けされていません

編集

それについて本当に確信しています。mySQLのマニュアルを再確認することをお勧めします。私はそれについてかなり確信しています、そしてそれは私が今それをチェックしたことを知っているのは良いことです、そしてvarchar(255)は確かにvarchar(20)とは異なります。

INT(20)=> INTとVarchar(255)=> varchar(20)を混同したと思います

于 2011-12-26T12:54:46.807 に答える