0

約 150 万のレコードを含むセット テーブル (MySQL) をネストしました。テーブル構造は次のとおりです。

id | name | root_id | lft | rgt | level

すべての親レコードの名前とレコード名を含む文字列を取得する必要があります。これを「full_name」と呼びましょう。たとえば、

"United States, California, Los Angeles"

「ロサンゼルス」レコード用。

次のように、1 つのレコードのすべての名前をクエリできます。

SELECT parent.name
FROM location AS node,
     location AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
        AND parent.root_id=node.root_id AND node.id=:id
ORDER BY parent.level

implode() を使用して full_name を構築する

ただし、このリクエストは 1 つのレコードに対してのみ機能し、複数の呼び出しに対しては動作が遅すぎます。だから今、'full_name' を Sphinx インデックス (またはおそらく MySQL に直接) に追加したいと思います。

質問:

  • 各レコードに対して 'full_name' を選択して Sphinx インデックスに配置するような SQL クエリを作成することは可能ですか? このような状況では、これが理想的なソリューションになると思います。

  • また、「full_name」フィールドを追加して MySQL テーブルを更新しようとしましたが、更新リクエストが完了するまでに数日かかります。それはまったく良い考えですか?この更新を十分に速くすることは可能ですか?

  • PostgreSQL に移行して、階層的なリクエストを使用する必要があるのではないかと考えています (このデータベースの経験がないため、確信が持てません)。

ありがとうございました

4

1 に答える 1

0

When you say you are updating your table to add the full_name field, do you mean you are running the above query for every single record individually?

Really it shouldnt be that slow, do you have proper indexes on the table?

Regardless, you can make it even quicker, by only running one actual query, to get all records. The function here: http://www.sitepoint.com/hierarchical-data-database-2/

Can easily be modified, to update all recrds. Just rather than printing out an indented list, each iteration of the loop should run an update statement. As well as maintaining the $right array, need to maintain a list of strings. Where add/remove to right add you another array at the same time.

// start with an empty $right stack
$right = array();
$names = array();

// now, retrieve whole tree
$result = mysql_query('SELECT id, name, full_name, lft, rgt FROM location ORDER BY lft ASC');

// update each row
while ($row = mysql_fetch_array($result)) {
    // only check stack if there is one
    if (count($right)>0) {
        // check if we should remove a node from the stack
        while ($right[count($right)-1]<$row['rgt']) {
            array_pop($right);
            array_pop($names);
        }
    }

    // add this node to the stack
    $right[] = $row['rgt'];
    $names[] = $row['name'];

    if (empty($row['full_name'])) {
        mysql_query("UPDATE location SET full_name='".mysql_real_escape_string(implode(', ',$names))."' WHERE id=".intval($row['id']));
    }
}

And if that is still slow, rather than updating the original table, insert the full_name (along with the id) into a new table - that doesnt have any indexes. Alter the table to add index on the id column, then run a multi-table update, to update the main table from the temporally table. This will be quicker, because its not updating the main indexes piecemeal, its doing it on one big batch.

于 2012-12-15T00:11:51.657 に答える