sql >> データベース >  >> RDS >> Mysql

読み取りと書き込みを多用するアプリケーションの場合、URLをmysqlに保存するための最良の方法

    私はこれを幅広く扱ってきましたが、私の一般的な哲学は使用頻度法を使用することです。面倒ですが、データに対して優れた分析を実行できます。

    CREATE TABLE URL (
       ID            integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
       DomainPath    integer unsigned NOT NULL,
       QueryString   text
    ) Engine=MyISAM;
    
    CREATE TABLE DomainPath (   
       ID            integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
       Domain        integer unsigned NOT NULL,
       Path          text,
       UNIQUE (Domain,Path)
    ) Engine=MyISAM;
    
    CREATE TABLE Domain (   
       ID            integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
       Protocol      tinyint NOT NULL,
       Domain        varchar(64)
       Port          smallint NULL,
       UNIQUE (Protocol,Domain,Port)
    ) Engine=MyISAM;
    

    原則として、単一のドメインには同様のパスがありますが、パスごとに異なるクエリ文字列があります。

    私はもともと、すべての部分を1つのテーブル(プロトコル、ドメイン、パス、クエリ文字列)でインデックス付けするように設計しましたが、上記の方がスペースをあまり消費せず、より良いデータを取得するのに役立つと思います。

    テキスト 遅くなる傾向があるので、使用後に「Path」をvarcharに変更できます。ほとんどのサーバーはURLが約1Kで停止しますが、大きなサーバーをいくつか見たことがあり、データが失われないという側面でエラーが発生します。

    取得クエリは面倒ですが、コードで抽象化しても問題ありません:

    SELECT CONCAT(
        IF(D.Protocol=0,'http://','https://'),
        D.Domain,
        IF(D.Port IS NULL,'',CONCAT(':',D.Port)), 
        '/', DP.Path, 
        IF(U.QueryString IS NULL,'',CONCAT('?',U.QueryString))
    )
    FROM URL U
    INNER JOIN DomainPath DP ON U.DomainPath=DP.ID
    INNER JOIN Domain D on DP.Domain=D.ID
    WHERE U.ID=$DesiredID;
    

    非標準の場合はポート番号を保存します(httpの場合は非80、httpsの場合は非443)。それ以外の場合は、含まれてはならないことを示すためにNULLとして保存します。 (MySQLにロジックを追加することはできますが、かなり醜くなります。)

    私は常に(または決して)パスから「/」と「?」を削除します。スペース節約のためにQueryStringから。損失だけが区別することができます

    http://www.example.com/
    http://www.example.com/?
    

    重要な場合は、それを削除せずに含めるようにタックを変更します。技術的には

    http://www.example.com 
    http://www.example.com/
    

    同じなので、パススラッシュを削除しても問題ありません。

    したがって、解析するには:

    http://www.example.com/my/path/to/my/file.php?id=412&crsource=google+adwords
    

    parse_urlのようなものを使用します PHPで生成するもの:

    array(
        [scheme] => 'http',
        [host] => 'www.example.com',
        [path] => '/my/path/to/my/file.php',
        [query] => 'id=412&crsource=google+adwords',
    )
    

    次に、チェック/挿入します(適切なロックを使用して、表示されていません):

    SELECT D.ID FROM Domain D 
    WHERE 
        D.Protocol=0 
        AND D.Domain='www.example.com' 
        AND D.Port IS NULL
    

    (存在しない場合)

    INSERT INTO Domain ( 
        Protocol, Domain, Port 
    ) VALUES ( 
        0, 'www.example.com', NULL 
    );
    

    次に、 $ DomainIDがあります。 今後...

    次に、DomainPathに挿入します:

    SELECT DP.ID FORM DomainPath DP WHERE 
    DP.Domain=$DomainID AND Path='/my/path/to/my/file.php';
    

    (存在しない場合は、同様に挿入してください)

    次に、 $ DomainPathIDがあります。 今後...

    SELECT U.ID FROM URL 
    WHERE 
        DomainPath=$DomainPathID 
        AND QueryString='id=412&crsource=google+adwords'
    

    必要に応じて挿入します。

    ここで、重要なことに注意してください。 、上記のスキームは高性能サイトでは遅くなります。 SELECT を高速化するには、ある種のハッシュを使用するようにすべてを変更する必要があります s。要するに、テクニックは次のようなものです:

    CREATE TABLE Foo (
         ID integer unsigned PRIMARY KEY NOT NULL AUTO_INCREMENT,
         Hash varbinary(16) NOT NULL,
         Content text
    ) Type=MyISAM;
    
    SELECT ID FROM Foo WHERE Hash=UNHEX(MD5('id=412&crsource=google+adwords'));
    

    単純にするために上記から意図的に削除しましたが、選択のためにTEXTを別のTEXTと比較するのは遅く、非常に長いクエリ文字列では壊れます。固定長のインデックスも使用しないでください。固定長のインデックスも破損します。精度が重要な任意の長さの文字列の場合、ハッシュの失敗率は許容範囲内です。

    最後に、可能であれば、MD5ハッシュクライアント側を実行して、MD5操作を実行するためにサーバーに大きなblobを送信する手間を省きます。最新の言語のほとんどは、MD5組み込みをサポートしています:

    SELECT ID FROM Foo WHERE Hash=UNHEX('82fd4bcf8b686cffe81e937c43b5bfeb');
    

    しかし、私は逸脱します。



    1. SQLOUTPUTストアドプロシージャがExecuteReaderで機能しない

    2. AccessのODBCリンクテーブルへの一括INSERTのパフォーマンスを向上させる方法は?

    3. PostgreSQLでピボットテーブルを作成する方法

    4. AtlassianBitbucketを使用したPostgreSQLバージョン管理