2017-02-22 8 views
-1

私は複雑な問題がありますが、具体的な内容に入るのではなく、次のように簡略化しました。郵便番号でユーザーのメタデータを保存/照会する方法

システムのユーザーが、郵便番号ごとにさまざまなサービスの優先度を適用できるシステムを構築しようとしているとしましょう。このシステムは、そうのような4つのテーブルを持っているでしょう...

CREATE TABLE `zip_code` (
    `zip` varchar(7) NOT NULL DEFAULT '', 
    `lat` float NOT NULL DEFAULT '0', 
    `long` float NOT NULL DEFAULT '0' 
    PRIMARY KEY (`zip`,`lat`,`long`), 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

CREATE TABLE `user` (
    `user_id` int(10) NOT NULL AUTO_INCREMENT 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

CREATE TABLE `service` (
    `service_id` int(10) NOT NULL AUTO_INCREMENT 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

CREATE TABLE `service_priority` (
    `user_id` int(10) NOT NULL', 
    `service_id` int(10) NOT NULL', 
    `zip` varchar(7) NOT NULL, 
    `priority` tinyint(1) NOT NULL 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

は今も私たちは45000ジップコード、数百のサービスと数千のユーザーを持っていることを言うと、どのユーザーが同じ優先度を持つことができないことができます同じ郵便番号で同じサービスの別のユーザーとして

特定の郵便番号が指定されている場合、radius、service、およびuser_idは、そのサービスのその半径内の他のすべての郵便番号に対して利用可能な最高の優先度を返します。

また、このデータを再構成するための提案を知りたいと考えています。

ここで起こっている問題は、実際にはおそらく10000行が大きいにも関わらず、ユーザーベースが増えるにつれて、service_priorityテーブルは理論上45000行が大きくなることになります。

これらの問題を緩和するにはどうすればよいですか?

+1

郵便番号には1つの緯度/経度がありません。ポリゴンなので、どのように動作するのかよくわかりません。あなたはおそらく、郵便番号情報のサードパーティのデータベースを調べることを検討したいでしょう。浮動小数点数ではなく、空間型を使用することもできます。 [MySQLの空間的な拡張](https://dev.mysql.com/doc/refman/5.7/en/spatial-extensions.html)、またはそれより優れた[PostgreSQLのGIS拡張](http://postgis.net/)があります。 。または、任意のロケーションサービスにサードパーティを使用して調べてください。 – Schwern

+1

各ジップにシンプルな重心を使用しているようですね? 45Kは米国の郵便番号のように聞こえます。 'VARCHAR(7)'は間違いのように聞こえます。 'CHAR(5)'でなければなりません。または「中位(5)無指定ゼロ詰め」。 –

+0

これらのコメントはどちらも私にとっては正しいと思います。実際には郵便番号の中心点を使用しているため、実際の郵便番号の境界線については正確ではありません。また、それは現在のところ米国のzipですが、DBには英数字のカナダのzipもあります。理論的には、いつかカナダでビジネスをすることがあります。今すぐ空間拡張の学習だけ、ありがとう。 –

答えて

0

InnoDBに切り替えます。

zip_codeテーブルには、特定のジップに複数の行が本当に必要な場合以外は、おそらくPRIMARY KEY(zip)になるはずです。

「はユーザーが同じ郵便番号で同じサービスのための別のユーザーと同じ優先順位が持つことはできません」 - その後、あなたのクエリが

SELECT sp.* 
    FROM (SELECT b.zip 
      FROM (SELECT lat, lng FROM zip_code WHERE zip = '$zip') AS a 
      JOIN zip_code AS b 
      WHERE ... < $radius 
     ) AS z 
    JOIN service_priority AS sp 
    WHERE sp.zip = z.zip 
     AND sp.user_id = $user_id 
     AND sp.service_id = $service_id 
    ORDER BY sp.priority DESC 
    LIMIT 1 
のようなものに見えるかもしれ

service_priority : UNIQUE(service_id, user_id, zip) 

によって強制することができます

注:

  • インデックスは、上記、また、このクエリに合わせて調整されます。
  • 最も内側のクエリは、中心点のlat/lngを取得します。
  • 真ん中のクエリは、近くのジップを見つけることに焦点を当てています。多くの質問を見つけるために追加したタグを参照してください。
  • 外部クエリは、ユーザーとサービスに基づいて結果をフィルタリングします。
  • 最後に、最も優先順位の高い行が選択されます。