2017-04-13 10 views
0

私はこのようなテーブルを持っている:MySQLのGROUP - クエリの最適化

CREATE TABLE `purchase` (
    `fact_purchase_id` binary(16) NOT NULL, 
    `purchase_id` int(10) unsigned NOT NULL, 
    `purchase_id_primary` int(10) unsigned DEFAULT NULL, 
    `person_id` int(10) unsigned NOT NULL, 
    `person_id_owner` int(10) unsigned NOT NULL, 
    `service_id` int(10) unsigned NOT NULL, 
    `fact_count` int(10) unsigned NOT NULL DEFAULT '0', 
    `fact_type` tinyint(3) unsigned NOT NULL, 
    `date_fact` date NOT NULL, 
    `purchase_name` varchar(255) DEFAULT NULL, 
    `activation_price` decimal(7,2) unsigned NOT NULL DEFAULT '0.00', 
    `activation_price_total` decimal(7,2) unsigned NOT NULL DEFAULT '0.00', 
    `renew_price` decimal(7,2) unsigned DEFAULT '0.00', 
    `renew_price_total` decimal(7,2) unsigned NOT NULL DEFAULT '0.00', 
    `activation_cost` decimal(7,2) unsigned DEFAULT '0.00', 
    `activation_cost_total` decimal(7,2) unsigned NOT NULL DEFAULT '0.00', 
    `renew_cost` decimal(7,2) unsigned DEFAULT '0.00', 
    `renew_cost_total` decimal(7,2) unsigned NOT NULL DEFAULT '0.00', 
    `date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    PRIMARY KEY (`fact_purchase_id`), 
    KEY `purchase_id_idx` (`purchase_id`), 
    KEY `person_id_idx` (`person_id`), 
    KEY `person_id_owner_idx` (`person_id_owner`), 
    KEY `service_id_idx` (`service_id`), 
    KEY `fact_type_idx` (`fact_type`), 
    KEY `renew_price_idx` (`renew_price`), 
    KEY `renew_cost_idx` (`renew_cost`), 
    KEY `renew_price_year_idx` (`renew_price_year`), 
    KEY `renew_cost_year_idx` (`renew_cost_year`), 
    KEY `date_created_idx` (`date_created`), 
    KEY `purchase_id_primary_idx` (`purchase_id_primary`), 
    KEY `fact_count` (`fact_count`), 
    KEY `renew_price_year_total_idx` (`renew_price_total`), 
    KEY `renew_cost_year_total_idx` (`renew_cost_total`), 
    KEY `date_fact` (`date_fact`) USING BTREE, 
    CONSTRAINT `purchase_person_fk` FOREIGN KEY (`person_id`) REFERENCES `person` (`person_id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 
    CONSTRAINT `purchase_person_owner_fk` FOREIGN KEY (`person_id_owner`) REFERENCES `person` (`person_id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 
    CONSTRAINT `purchase_service_fk` FOREIGN KEY (`service_id`) REFERENCES `service` (`service_id`) ON DELETE NO ACTION ON UPDATE NO ACTION 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

私はこのクエリを起動しています:

SELECT 
    purchase.date_fact, 
    UNIX_TIMESTAMP(purchase.date_fact), 
    COUNT(DISTINCT purchase.purchase_id) AS Num 
FROM 
    purchase 
WHERE 
    purchase.date_fact >= '2017-01-01' 
    AND purchase.date_fact <= '2017-01-31' 
    AND purchase.fact_type = 3 
    AND purchase.purchase_id_primary IS NULL 
GROUP BY purchase.date_fact 

表は5.629.670レコードの合計が含まれており、私はこれらの結果を取得するクエリにEXPLAINを実行している:

  • rows = 2.814.835
  • possible_keys = fact_type_idx,purchase_id_primary_idx,date_fact
  • key = fact_type_idx
  • key_len = 1
  • ref = const
  • filtered = 25.00
  • Extra =
  • Using index condition;Using where;Using filesort

クエリは30-35セコを取りndsが実行されます。これは待つのには時間がかかります。

問題は、GROUP BYがfilesortを適用することです。 ORDER BY NULLをクエリに適用しても、何も変更されません。

私はおそらくカバーインデックスを使用することができますが、このクエリではdate_factが必要です:どのフィールドを使用できますか?

GROUP BYでファイルを開くことを避けるにはどうすればよいですか?クエリーをより高速化するためにクエリを最適化するにはどうすればよいですか?

私はこの表を統計目的(OLAP)に使用しています。たぶん、この目的のためのより良いDBMSはありますか?

私はMySql Server 5.7.17を実行しています。

は、このクエリのためにあなたに

答えて

2

ありがとう:

SELECT p.date_fact, UNIX_TIMESTAMP(p.date_fact), 
     COUNT(DISTINCT p.purchase_id) AS Num 
FROM purchase p 
WHERE p.date_fact >= '2017-01-01' AND 
     p.date_fact <= '2017-01-31' AND 
     p.fact_type = 3 AND 
     p.purchase_id_primary IS NULL 
GROUP BY p.date_fact; 

私は(fact_type, purchase_id_primary, date_fact, purchase_id)に複合インデックスをお勧めします。最初の2つのキーはWHEREに等しい条件を持ちます。 3つ目は不等式を持ち、4つ目はインデックスがクエリを「カバー」することができます(クエリのすべての列がインデックスにあります)。

私も追加します:COUNT(DISTINCT)が必要ない場合は、使用しないでください。 purchase_idは既にpurchaseで一意である可能性があります。