Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql MariaDB/PostreSQL-查询优化_Mysql_Sql_Postgresql_Query Optimization_Mariadb - Fatal编程技术网

Mysql MariaDB/PostreSQL-查询优化

Mysql MariaDB/PostreSQL-查询优化,mysql,sql,postgresql,query-optimization,mariadb,Mysql,Sql,Postgresql,Query Optimization,Mariadb,我需要生成一些数字,我设计了一个查询,以获得客户想要的结果。 此查询基于包含一百万条记录的表。 我通常使用MariaDB来实现这一点,我会在7秒内得到一个结果。 这个执行时间非常合适,但我希望再次优化以提高我的技能。 经过一些研究,我看到一些帖子说MySQL很好,但不是在记录数大于1M的表上,你必须打开PostgreSQL多次引用的其他东西。 所以我安装了PostgreSQL,并复制了我的表、索引和数据。 我执行了相同的查询,在12秒内得到了一个结果 我不太懂PostgreSQL,我想我没有使用

我需要生成一些数字,我设计了一个查询,以获得客户想要的结果。 此查询基于包含一百万条记录的表。 我通常使用MariaDB来实现这一点,我会在7秒内得到一个结果。 这个执行时间非常合适,但我希望再次优化以提高我的技能。 经过一些研究,我看到一些帖子说MySQL很好,但不是在记录数大于1M的表上,你必须打开PostgreSQL多次引用的其他东西。 所以我安装了PostgreSQL,并复制了我的表、索引和数据。 我执行了相同的查询,在12秒内得到了一个结果

我不太懂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
我用图表来完成我的问题

下面是创建表:

/*!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字符类型不值得规范化。5字符cp也是如此

除非您真的希望输出行全部为零,否则请将此添加到“2016-01-01”和“2016-12-31”之间的dhu.date,然后再添加到GROUP BY

请按照我的建议进行多:多模式设计。这可能会加快MySQL的查询速度。我不知道同样的原则是否适用于博士后


改为内部连接fa、patient和categorie。没错,查询更具可读性,但执行时间相同。条件聚合/筛选GIY您是否可以在sqlfiddle.com或db-fiddle.com上发布包含任何索引的表/数据,然后回复此评论?另外,你试过使用EXPLAIN吗?请在mysql上运行ANALYZE TABLE,在postgres上运行真空分析,发布表定义,在mysql上解释查询,在postgres上解释分析。谢谢。我删除了您处理的项目,并添加了几个。我添加了反向索引cat_id,patient_id,但没有任何影响。我从未想过使用这个,谢谢您的建议;我不能使用WHERE YEARdhu.date=2016,因为我需要计算范围[2013-01-01;2016-12-31],我认为执行时间只来自运行在桌面上的虚拟机Centos/1Go RAM。在FWIW中,将属性拉出到由自动增量索引的查找表中的设计不是规范化的。它与任何正规形式都没有关系。我不知道它的名字,除了制作一个自动递增索引的查找表外:-好吧,我叫它马尔蒂拜;