1

MySQL にデータを保存し、現在の日付に基づいてクエリを実行したいと考えています。そうするためのベストプラクティスは何かを知りたいです。

毎日のデータの合計を保存したいので、合計データのクエリは高速になります。次のようにテーブルをモデル化することを考えました。

TotalsByCountry
- Year
- Month
- Day
- countryId
- totalNumber

特定の日と特定の国について合計を照会する場合、年、月、日、および国 ID の 4 つの列に基づいてテーブルを照会します。

これが良い方法なのか、それとも月、日、年を保持するデータに 1 つの列を使用し、datetime 列と countryId の 2 つの列のみをクエリするなど、より良い方法があるかどうかを知りたかったのです。

テーブルをモデル化する正しい方法を選択するのに助けが必要です。また、性別に基づいて合計を格納する別のテーブルを作成したいので、それも考慮してください。

データの変更をリアルタイムで表示したいので、データには頻繁に、おそらくリアルタイムでアクセスする必要があります。私はasp.netでWebアプリを開発し、おそらくWebソケットを使用して、ユーザーのデータをリアルタイムで更新する一定の接続を作成します。そのため、データが変更されると、リアルタイムでユーザーの Web ページに反映されます。そのため、多くのクエリに対応できるテーブル モデリングが必要です。キャッシュを数秒間使用するので、データベースに負荷をかけすぎます。

十分な情報を提供したことを願っています。そうでない場合は、コメントしてください。返信します。

4

2 に答える 2

3

日付 (年/月/日) の個々の要素を格納するために 3 つの個別の列があると、挿入のパフォーマンスとディスク容量に関して、データベースに不要なオーバーヘッドが追加されます。

やりたいことはDATETIME、日付と時刻を格納する単一の列を用意し、複合インデックスを設定すること(countryId, datetime_col)です。

特定の日または月に基づいてすべての行をクエリしたい場合でも、クエリを正しい方法で記述し、DATETIME 列をラップしないようにしていれば、MySQL は DATETIME フィールドのインデックスを利用できます。条件チェックを実行するときの関数内。

インデックスを利用できるようにクエリを作成する方法は次のとおりです。

-- Get the sum of totalNumber of all rows based on current day
-- where countryId = 1

SELECT SUM(totalNumber) AS totalsum
FROM   tbl
WHERE  countryId = 1 AND
       datetime_col >= CAST(CURDATE() AS DATETIME) AND
       datetime_col <  CAST(CURDATE() + INTERVAL 1 DAY AS DATETIME)

そのままの DATETIME 列で比較を行うことにより、クエリは sargable (つまり、インデックス範囲スキャンを利用できる) のままになり、MySQL はインデックスを使用して行をすばやく検索できるようになります。

一方、比較を行うために DATETIME 列を関数内にラップしようとすると、次のようになります。

-- Get the sum of totalNumber of all rows based on current day
-- where countryId = 1

SELECT SUM(totalNumber) AS totalsum
FROM   tbl
WHERE  countryId = 1 AND
       DATE(datetime_col) = CURDATE()

...DATE()列をラップする関数はクエリを効果的に非サーガブルとしてレンダリングし、DATETIME 列を含む設定したあらゆる種類のインデックスが使用されないため、非常に非効率的です。

また、当月のすべての行の合計を効率的に照会することもできます。

-- Get the sum of totalNumber of all rows based on current month
-- where countryId = 1

SELECT SUM(totalNumber) AS monthsum
FROM   tbl
WHERE  countryId = 1 AND
       datetime_col >= CAST(CONCAT(YEAR(NOW()), '-', MONTH(NOW()), '-01') AS DATETIME) AND
       datetime_col <  CAST(CONCAT(YEAR(NOW()), '-', MONTH(NOW()), '-01') AS DATETIME) + INTERVAL 1 MONTH

そして、現在の年内

-- Get the sum of totalNumber of all rows based on current year
-- where countryId = 1

SELECT SUM(totalNumber) AS yearsum
FROM   tbl
WHERE  countryId = 1 AND
       datetime_col >= CAST(CONCAT(YEAR(NOW()), '-01-01') AS DATETIME) AND
       datetime_col <  CAST(CONCAT(YEAR(NOW()), '-01-01') AS DATETIME) + INTERVAL 1 YEAR
于 2012-07-15T23:05:32.250 に答える
1

私の主張は次のとおりです。データベースのルックアップを高速化したい場合は、インデックスを使用する適切に構築されたクエリが必要です。あなたのアプローチには4つのインデックスが必要です(つまり、挿入が遅くなります)。単一の日付列を使用すると、必要なインデックスは2つだけになります。また、日付範囲を検索する必要がある場合は、クエリの複雑さが増します。

于 2012-07-15T22:23:38.913 に答える