-1

私は次のクエリ (およびそれに類似した他のクエリ) と格闘してきましたが、何かが足りないか、間違ったタイプのデータベースまたは何かを使用しているように感じます。

このクエリを使用して、過去 10 年間に英国と特定の都市で、年間の新しい映画の総数と上映が中止された (閉鎖された) 映画の総数を取得します。クエリは、何年にもわたって多くの町や郡に対しても実行されます。

他のクエリも同様のことを行い、UNION ALLオープニングまたはクロージングの記録年を取得するクエリの最後に a を追加することがあります。

年次データの代わりに月次データと四半期データに対して実行されるクエリもあり、特定の四半期 (例: 第 3 四半期) または月 (例: 3 月) の過去のオープン/クローズを比較するだけのクエリもあります。

2012 年の英国とロンドンを比較するクエリは次のとおりです。

SELECT inc.opening_year as year, inc.number_of_films as opens,
    diss.number_of_films as closures, inc.uk_films as uk_opens,
    diss.uk_films as uk_closures
FROM
(SELECT film_db.opening_year, uk.number_of_films as uk_films,
        COUNT(film_db.id_film_db) as number_of_films
    FROM film_db
    JOIN postcodes ON id_postcodes = opening_postcode_id
    JOIN towns ON id_towns = town_id AND town = 'London'
    JOIN (SELECT opening_year, COUNT(film_db.id_film_db) as number_of_films
            FROM film_db
            WHERE opening_year <= 2012 AND opening_year >= (2012 - 10)
            GROUP BY opening_year
        ) uk ON uk.opening_year = film_db.opening_year
    WHERE film_db.opening_year <= 2012 AND film_db.opening_year >= (2012 - 10)
    GROUP BY film_db.opening_year
    ORDER BY film_db.opening_year DESC
) inc
JOIN
(SELECT film_db.closing_year, uk.number_of_films as uk_films,
        COUNT(film_db.id_film_db) as number_of_films
    FROM film_db
    JOIN postcodes ON id_postcodes = postcode_id
    JOIN towns ON id_towns = town_id AND town = 'London'
    JOIN (SELECT closing_year, COUNT(film_db.id_film_db) as number_of_films
            FROM film_db
            WHERE film_db.closing_year <= 2012 AND film_db.closing_year >= (2012 - 10)
            GROUP BY film_db.closing_year
        ) uk ON uk.closing_year = film_db.closing_year
    WHERE film_db.closing_year <= 2012 AND film_db.closing_year >= (2012 - 10)
    GROUP BY film_db.closing_year
    ORDER BY film_db.closing_year DESC
) diss ON diss.closing_year = inc.opening_year

デシベルのSHOW CREATE TABLE出力は次のとおりです。

フィルム データベース:

CREATE TABLE `film_db` (
  `id_film_db` int(11) NOT NULL AUTO_INCREMENT,
  `film_name` varchar(255) DEFAULT NULL,
  `category` varchar(100) DEFAULT NULL,
  `status` varchar(50) DEFAULT NULL,
  `opening_date` date DEFAULT NULL,
  `opening_year` int(4) DEFAULT NULL,
  `opening_month` int(2) DEFAULT NULL,
  `opening_quarter` int(1) DEFAULT NULL,
  `closing_date` date DEFAULT NULL,
  `closing_year` int(4) DEFAULT NULL,
  `closing_month` int(2) DEFAULT NULL,
  `closing_quarter` int(1) DEFAULT NULL,
  `datetime` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `postcode_id` int(4) NOT NULL DEFAULT '0',
  `opening_postcode_id` int(4) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id_film_db`),
  KEY `opening_date` (`opening_date`),
  KEY `status` (`status`),
  KEY `postcode_id` (`postcode_id`),
  KEY `type` (`category`),
  KEY `opening_year` (`opening_year`),
  KEY `opening_month` (`opening_month`,`opening_year`) USING BTREE,
  KEY `opening_quarter` (`opening_quarter`,`opening_year`) USING BTREE,
  KEY `closing_year` (`closing_year`),
  KEY `closing_month` (`closing_year`,`closing_month`),
  KEY `closing_quarter` (`closing_year`,`closing_quarter`),
  KEY `closing_date` (`closing_date`),
  KEY `opening_closing_date` (`opening_date`,`closing_date`),
  KEY `opening_postcode` (`opening_postcode_id`),
  FULLTEXT KEY `film_name` (`film_name`)
) ENGINE=MyISAM AUTO_INCREMENT=10649173 DEFAULT CHARSET=utf8

郵便番号:

CREATE TABLE `postcodes` (
  `id_postcodes` int(4) NOT NULL AUTO_INCREMENT,
  `postcode` varchar(9) NOT NULL,
  `town_id` int(4) NOT NULL,
  `lat` float NOT NULL,
  `lng` float NOT NULL,
  PRIMARY KEY (`id_postcodes`),
  UNIQUE KEY `postcode` (`postcode`) USING BTREE,
  KEY `town` (`town_id`)
) ENGINE=MyISAM AUTO_INCREMENT=5705 DEFAULT CHARSET=latin1

町:

CREATE TABLE `towns` (
  `id_towns` int(4) NOT NULL AUTO_INCREMENT,
  `town` varchar(150) NOT NULL,
  `county_id` int(3) NOT NULL,
  PRIMARY KEY (`id_towns`),
  KEY `county` (`county_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1606 DEFAULT CHARSET=latin1

EXPLAIN EXTENDED出力は次のとおりです。

1   PRIMARY <derived2>      ALL                                                                                                                     11      100 
1   PRIMARY <derived4>      ALL                                                                                                                     11      100     Using where; Using join buffer
4   DERIVED <derived5>      ALL                                                                                                                     11      100     Using where; Using temporary; Using filesort
4   DERIVED film_db         ref     postcode_id,closing_year,closing_month,closing_quarter  closing_year    5   uk.closing_year                     2       100     Using where
4   DERIVED postcodes       eq_ref  PRIMARY,town                                            PRIMARY         4   film_db.postcode_id                 1       100 
4   DERIVED towns           eq_ref  PRIMARY                                                 PRIMARY         4   postcodes.town_id                   1       100     Using where
5   DERIVED film_db         ALL     closing_year,closing_month,closing_quarter                                                                      9895680 47.66   Using where; Using temporary; Using filesort
2   DERIVED <derived3>      ALL                                                                                                                     11      100     Using where; Using temporary; Using filesort
2   DERIVED film_db         ref     opening_year,opening_postcode                           opening_year    5   uk.opening_year                     3       100     Using where
2   DERIVED postcodes       eq_ref  PRIMARY,town                                            PRIMARY         4   film_db.opening_postcode_id         1       100 
2   DERIVED towns           eq_ref  PRIMARY                                                 PRIMARY         4   postcodes.town_id                   1       100     Using where
3   DERIVED film_db         ALL     opening_year                                                                                                    9895680 54.53   Using where; Using temporary; Using filesort

ご覧のとおり、MySQL は、film_dbテーブルでのフィルタリングによってパフォーマンスに違いが生じるとは考えていないため、キーを使用しません。

そう:

インデックスをより適切に使用するために、このクエリを改善できますか?

クエリがより高速に実行されるように、インデックス作成を改善できますか?

複雑な条件と結合を持つエントリの数をカウントすることに主に関心があるこの種のクエリの代わりに使用する必要がある別のデータベース タイプ (MySQL ではない) はありますか?

4

1 に答える 1

1

これは私が最初に試すことです:

CREATE TABLE opens 
SELECT opening_year, COUNT(film_db.id_film_db) as number_of_films
FROM film_db
WHERE opening_year <= 2012 AND opening_year >= (2012 - 10)
GROUP BY opening_year

CREATE TABLE closures 
SELECT closing_year, COUNT(film_db.id_film_db) as number_of_films
FROM film_db
WHERE film_db.closing_year <= 2012 AND film_db.closing_year >= (2012 - 10)
GROUP BY film_db.closing_year

現在使用しているサブセレクトの代わりに、これら 2 つのテーブルを使用します。

他のクエリも同様のことを行い、オープニングまたはクロージングの記録年を取得するクエリの最後に UNION ALL を追加することがあります。年次データの代わりに月次データと四半期データに対して実行されるクエリもあり、特定の四半期 (例: Q3) または月 (例: 3 月) の過去のオープン/クローズを比較するクエリもあります。

これらの選択をより頻繁に実行すると、opens/closures テーブルの内容が変更されると思います。したがって、このようなクエリを実行するたびにこれらのテーブルを再構築する必要はありません。


インデックスをより適切に使用するために、このクエリを改善できますか? クエリがより高速に実行されるように、インデックス作成を改善できますか? 複雑な条件と結合を持つエントリの数をカウントすることに主に関心があるこの種のクエリの代わりに使用する必要がある別のデータベース タイプ (MySQL ではない) はありますか?

もちろん、他にも多くの可能な改善があります。MySQL にインデックスを使用させる方法があるはずです。db エンジンは個別のインデックスを結合できないことに注意してください。つまり、この場合、index onopening_postcode_idと index onopening_yearを結合することはできません。どちらも使用されていない理由はわかりませんが、これら 2 つのようなインデックスがこのクエリを改善することは確かです。

KEY `opening_year_postcode` (`opening_year`, `opening_postcode_id`)
KEY `closing_year_postcode` (`closing_year`, `postcode_id`)

このSOの回答を参照してください https://stackoverflow.com/a/6295744/176569


私が何年にもわたって学んだことは、この種のパフォーマンス調整はかなり段階的なプロセスです。いくつかのトリックを試し、パフォーマンスの向上を評価し、最終的には 1 つまたは 2 つだけ適用する必要があります。

現時点では、他のデータベース ベンダーのために MySQL をやめることは考えていません。パフォーマンスの問題の原因は、おそらく MySQL ではありません。

于 2012-08-24T10:35:21.690 に答える