簡體   English   中英

MariaDB / PostreSQL-查詢優化

[英]MariaDB/PostreSQL - Query optimization

我需要產生一些數字,我設計了一個查詢來獲取“客戶”所需的結果。 該查詢基於包含一百萬條記錄的表。 我通常為此使用MariaDB,並在大約7s內得到結果。 這個執行時間非常合適,但我希望再次進行優化以提高自己的技能。 經過一番研究,我發現一些帖子說:“ MySQL很好,但不能在表> 1M的記錄上使用,您必須啟用其他功能” PostgreSQL被引用了好幾次。 因此,我安裝了PostgreSQL,並復制了表,索引和數據。 我執行了相同的查詢,結果在大約12s內

我對PostgreSQL的了解較少,我想我沒有使用該語言固有的特性。 因此,現在我留在MariaDB上。 您有縮短執行時間的想法嗎?

這是我的查詢:

select categorie.cat
,dhu_type.type
,COUNT(DISTINCT(
    CASE WHEN dhu.date between '2013-01-01' and '2013-12-31'    
    THEN dhu.id
    END )

  ) AS "2013"
,COUNT(DISTINCT(
    CASE WHEN dhu.date between '2014-01-01' and '2014-12-31'    
    THEN dhu.id
    END )

  ) AS "2014"
,COUNT(DISTINCT(
    CASE WHEN dhu.date between '2015-01-01' and '2015-12-31'     
    THEN dhu.id
    END )

  ) AS "2015"
,COUNT(DISTINCT(
    CASE WHEN dhu.date between '2016-01-01' and '2016-12-31'       
    THEN dhu.id
    END )

  ) AS "2016"
from dhu
inner join dhu_type on dhu.type_id = dhu_type.id
inner join patient on dhu.patient_id=patient.id
inner join fa on patient.id = fa.patient_id
inner join categorie on categorie.id = fa.cat_id
group by cat,dhu_type.type

我用圖表完成了我的問題

在此處輸入圖片說明

這里是CREATE TABLE:

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;


CREATE TABLE IF NOT EXISTS `categorie` (
  `id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
  `cat` varchar(50) NOT NULL DEFAULT 'neonat',
  PRIMARY KEY (`id`,`cat`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `cp` (
  `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `cp` varchar(5) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `cp` (`cp`)
) ENGINE=InnoDB AUTO_INCREMENT=4096 DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `dhu` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `patient_id` int(10) unsigned NOT NULL,
  `date` date NOT NULL,
  `type_id` tinyint(3) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_dhu_patient` (`patient_id`),
  KEY `FK_dhu_dhu_type` (`type_id`),
  CONSTRAINT `FK_dhu_dhu_type` FOREIGN KEY (`type_id`) REFERENCES `dhu_type` (`id`),
  CONSTRAINT `FK_dhu_patient` FOREIGN KEY (`patient_id`) REFERENCES `patient` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=953590 DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `dhu_import` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `noip` bigint(10) unsigned zerofill NOT NULL,
  `date` date NOT NULL,
  `cp` varchar(5) NOT NULL,
  `type` varchar(4) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `noip` (`noip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `dhu_type` (
  `id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
  `type` varchar(4) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `type` (`type`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `dpt` (
  `dpt` tinyint(3) unsigned DEFAULT NULL,
  `abrev` char(3) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `fa` (
  `patient_id` int(10) unsigned NOT NULL,
  `cat_id` tinyint(3) unsigned NOT NULL,
  PRIMARY KEY (`patient_id`,`cat_id`),
  KEY `idx_cat_id_pat_id` (`cat_id`,`patient_id`),
  CONSTRAINT `FK_fa_patient` FOREIGN KEY (`patient_id`) REFERENCES `patient` (`id`),
  CONSTRAINT `FK_fa_categorie` FOREIGN KEY (`cat_id`) REFERENCES `categorie` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `fa_import` (
  `noip` bigint(10) unsigned zerofill NOT NULL,
  `cat` varchar(50) NOT NULL,
  PRIMARY KEY (`noip`,`cat`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

CREATE TABLE IF NOT EXISTS `patient` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `noip` bigint(10) unsigned zerofill NOT NULL,
  `cp_id` smallint(5) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_patient_cp` (`cp_id`),
  CONSTRAINT `FK_patient_cp` FOREIGN KEY (`cp_id`) REFERENCES `cp` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=262141 DEFAULT CHARSET=utf8;


/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

這里的說明查詢: 在此處輸入圖片說明

這是一個改進性能的修改(選擇categorie.id而不是categorie.cat):

在此處輸入圖片說明

這是我發現的最好的最佳查詢,謝謝@RickJames&@BillKarwin

select categorie.cat
,dhu_type.`type`
,t.`2013`
,t.`2014`
,t.`2015`
,t.`2016` 
from ( select fa.cat_id as catid
,dhu.type_id typid
,COUNT(DISTINCT(
    CASE WHEN dhu.date between '2013-01-01' and '2013-12-31'    
    THEN dhu.id
    END )

  ) AS "2013"
,COUNT(DISTINCT(
    CASE WHEN dhu.date between '2014-01-01' and '2014-12-31'    
    THEN dhu.id
    END )

  ) AS "2014"
,COUNT(DISTINCT(
    CASE WHEN dhu.date between '2015-01-01' and '2015-12-31'     
    THEN dhu.id
    END )

  ) AS "2015"
,COUNT(DISTINCT(
    CASE WHEN dhu.date between '2016-01-01' and '2016-12-31'       
    THEN dhu.id
    END )

  ) AS "2016"
from dhu
inner join patient on dhu.patient_id=patient.id
inner join fa on patient.id = fa.patient_id
group by fa.cat_id, dhu.type_id ) t

inner join categorie on t.catid = categorie.id
inner join dhu_type on t.typid = dhu_type.id

order by categorie.cat,dhu_type.`type`
  • MySQL可以處理十億行表。

  • 任何數據庫引擎都取決於磁盤的速度以及用於緩存的RAM的數量。

  • 教科書說要對所有內容進行規范化,但是我建議4字符type不值得進行規范化。 同上5字符cp

  • 除非您真的想要輸出全零的行,否則在GROUP BY之前WHERE dhu.date between '2016-01-01' and '2016-12-31'添加此WHERE dhu.date between '2016-01-01' and '2016-12-31'

  • 按照我的建議在這里很多:很多架構設計( fa )。 這樣可以加快對MySQL的查詢。 (我不知道同樣的原則是否適用於Postgres。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM