优化 PostgreSQL 中的 SQL 查询

Posted

技术标签:

【中文标题】优化 PostgreSQL 中的 SQL 查询【英文标题】:Optimize SQL query in PostgreSQL 【发布时间】:2015-09-10 08:16:03 【问题描述】:

我有一个 SQL 查询,速度很慢,也没有在 PostgreSQL 中找到我的索引。

查询:

select s.id as id,
   utt.count as menciones,
   ut.usuario as user_twitter,
   ut.id as id_user_twitter
from busquedas_busqueda bu
  join dashboards_tablaagregadatwitterdiaria s on s.busqueda_id = bu.id
  join dashboards_usuariotwitter_tablaagregadatwitterdiaria utt on utt.tabla_id = s.id
  join busquedas_usuario_twitter ut on ut.id = utt.usuario_id     
where bu.cuenta_id=74 and
  s.fecha_id >= 20150811 AND s.fecha_id <= 20150909 AND
  bu.corporativa=false
group by s.id, utt.count, ut.usuario,ut.id

查询计划如下:

Group  (cost=178870.19..179050.19 rows=14400 width=29)
  ->  Sort  (cost=178870.19..178906.19 rows=14400 width=29)
        Sort Key: s.id, utt.count, ut.usuario, ut.id 
         ->  Nested Loop  (cost=4657.19..177875.60 rows=14400 width=29) 
             ->  Hash Join  (cost=4657.19..52048.58 rows=14400 width=16)
                 Hash Cond: (utt.tabla_id = s.id) 
                 ->  Seq Scan on dashboards_usuariotwitter_tablaagregadatwitterdiaria utt  (cost=0.00..39092.46 rows=2174646 width=16)
                    ->  Hash  (cost=4645.87..4645.87 rows=906 width=4)
                          ->  Hash Join  (cost=13.73..4645.87 rows=906 width=4) 
                               Hash Cond: (s.busqueda_id = bu.id) 
                               ->  Seq Scan on dashboards_tablaagregadatwitterdiaria s  (cost=0.00..4111.32 rows=136470 width=8) 
                                      Filter: ((fecha_id >= 20150811) AND (fecha_id <= 20150909)) 
                                ->  Hash  (cost=13.69..13.69 rows=3 width=4) 
                                      ->  Bitmap Heap Scan on busquedas_busqueda bu  (cost=4.30..13.69 rows=3 width=4) 
                                           Recheck Cond: (cuenta_id = 74) 
                                             Filter: (NOT corporativa) 
                                               ->  Bitmap Index Scan on busquedas_busqueda_cuenta_id  (cost=0.00..4.30 rows=7 width=0)  
                                                  Index Cond: (cuenta_id = 74) 
              ->  Index Scan using busquedas_usuario_twitter_pkey on busquedas_usuario_twitter ut  (cost=0.00..8.73 rows=1 width=17) 
                 Index Cond: (id = utt.usuario_id) 

型号如下:

CREATE TABLE busquedas_busqueda
(
  id serial NOT NULL,
  nombre character varying(150) NOT NULL,
  cuenta_id integer,
  busqueda_real text NOT NULL,
  terminos_asociados text NOT NULL,
  terminos_excluyentes text NOT NULL,
  color character varying(7) NOT NULL,
  corporativa boolean,
  busqueda character varying(150) NOT NULL,
  predeterminada boolean,
  tipo_busqueda integer,
 CONSTRAINT busquedas_busqueda_pkey PRIMARY KEY (id),
 CONSTRAINT cuenta_id_refs_id_6ced8d50 FOREIGN KEY (cuenta_id)
  REFERENCES usuarios_cuenta (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED
 )

CREATE INDEX busquedas_busqueda_cuenta_id
ON busquedas_busqueda
USING btree
(cuenta_id);

CREATE TABLE busquedas_usuario_twitter
(
  id serial NOT NULL,
  nombre character varying(150),
  usuario character varying(150) NOT NULL,
  biografia text,
  numero_seguidores integer,
  numero_seguidos integer,
  localizacion character varying(100),
  zona_horaria character varying(100),
  fecha_actualizacion timestamp with time zone,
  numero_tweets double precision,
  lenguaje character varying(10),
  imagen character varying(300),
  id_twitter bigint,
  activo boolean NOT NULL,
  visibilidad_id integer,
  CONSTRAINT busquedas_usuario_twitter_pkey PRIMARY KEY (id),
  CONSTRAINT visibilidad_id_refs_id_5405f268 FOREIGN KEY (visibilidad_id)
  REFERENCES dashboards_visibilidad_twitter (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT busquedas_usuario_twitter_id_twitter_key UNIQUE (id_twitter),
  CONSTRAINT busquedas_usuario_twitter_usuario_uniq UNIQUE (usuario)
 )

 CREATE INDEX busquedas_usuario_twitter_visibilidad_id
 ON busquedas_usuario_twitter
 USING btree
 (visibilidad_id);


CREATE TABLE dashboards_tablaagregadatwitterdiaria
(
  id serial NOT NULL,
  busqueda_id integer NOT NULL,
  source_id integer NOT NULL,
  fecha_id integer,
  visibilidad_id integer NOT NULL,
  tipo_de_follower_id integer,
  menciones integer,
  tipo_menciones_id integer,
  sentimiento double precision NOT NULL,
  tipo_tweet character varying(50) NOT NULL,
  termino_encontrado character varying(200),
  pais_id integer,
  idioma_id integer,
  CONSTRAINT dashboards_tablaagregadatwitterdiaria_pkey PRIMARY KEY (id),
  CONSTRAINT busqueda_id_refs_id_3c681db2 FOREIGN KEY (busqueda_id)
  REFERENCES busquedas_busqueda (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT fecha_id_refs_id_614d33db FOREIGN KEY (fecha_id)
  REFERENCES dashboards_tiempo (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT idioma_id_refs_id_9cc00494 FOREIGN KEY (idioma_id)
  REFERENCES usuarios_idioma (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT pais_id_refs_id_7a261136 FOREIGN KEY (pais_id)
  REFERENCES usuarios_pais (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT source_id_refs_id_eca486c8 FOREIGN KEY (source_id)
  REFERENCES busquedas_source (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT tipo_de_follower_id_refs_id_a71669d3 FOREIGN KEY      (tipo_de_follower_id)
  REFERENCES dashboards_tipo_followers (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT tipo_menciones_id_refs_id_027149b5 FOREIGN KEY (tipo_menciones_id)
  REFERENCES dashboards_tipo_mencion (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT visibilidad_id_refs_id_c3fc21ae FOREIGN KEY (visibilidad_id)
  REFERENCES dashboards_visibilidad_twitter (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT dashboards_tablaagregadatwitterdiaria_busqueda_id_50f275f1_uniq      UNIQUE (busqueda_id, fecha_id, visibilidad_id, tipo_de_follower_id,  tipo_menciones_id, tipo_tweet, termino_encontrado, pais_id, idioma_id,  sentimiento)
)

CREATE INDEX dashboards_tablaagregadatwitterdiaria_busqueda_id
ON dashboards_tablaagregadatwitterdiaria
USING btree
(busqueda_id);


CREATE INDEX dashboards_tablaagregadatwitterdiaria_busqueda_idfecha_id
ON dashboards_tablaagregadatwitterdiaria
USING btree
(busqueda_id, fecha_id);


CREATE INDEX dashboards_tablaagregadatwitterdiaria_fecha_id
ON dashboards_tablaagregadatwitterdiaria
USING btree
(fecha_id);


CREATE INDEX dashboards_tablaagregadatwitterdiaria_idioma_id
ON dashboards_tablaagregadatwitterdiaria
USING btree
(idioma_id);


CREATE INDEX dashboards_tablaagregadatwitterdiaria_pais_id
ON dashboards_tablaagregadatwitterdiaria
USING btree
(pais_id);


CREATE INDEX dashboards_tablaagregadatwitterdiaria_source_id
ON dashboards_tablaagregadatwitterdiaria
USING btree
(source_id);


CREATE INDEX dashboards_tablaagregadatwitterdiaria_tipo_de_follower_id
ON dashboards_tablaagregadatwitterdiaria
USING btree
(tipo_de_follower_id);

CREATE INDEX dashboards_tablaagregadatwitterdiaria_tipo_menciones_id
ON dashboards_tablaagregadatwitterdiaria
USING btree
(tipo_menciones_id);

 CREATE INDEX dashboards_tablaagregadatwitterdiaria_visibilidad_id
ON dashboards_tablaagregadatwitterdiaria
USING btree
(visibilidad_id);



CREATE TABLE dashboards_usuariotwitter_tablaagregadatwitterdiaria
(
  id serial NOT NULL,
  tabla_id integer NOT NULL,
  usuario_id integer NOT NULL,
  nombre text,
  count double precision,
  CONSTRAINT dashboards_usuariotwitter_tablaagregadatwitterdiaria_pkey     PRIMARY KEY (id),
   CONSTRAINT tabla_id_refs_id_120e7c9e FOREIGN KEY (tabla_id)
  REFERENCES dashboards_tablaagregadatwitterdiaria (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT usuario_id_refs_id_4cb3ad7e FOREIGN KEY (usuario_id)
  REFERENCES busquedas_usuario_twitter (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
  CONSTRAINT dashboards_usuariotwitter_tablaagregadat_tabla_id_35fb3a75_uniq    UNIQUE (tabla_id, usuario_id, nombre)
  )

 CREATE INDEX dashboards_usuariotwitter_tablaagregadatwitterdiaria_tabla_id
 ON dashboards_usuariotwitter_tablaagregadatwitterdiaria
 USING btree
 (tabla_id);

CREATE INDEX dashboards_usuariotwitter_tablaagregadatwitterdiaria_usuario_id
ON dashboards_usuariotwitter_tablaagregadatwitterdiaria
USING btree
(usuario_id);

我尝试创建索引,并以几种不同的方式构造查询,但我没有得到优化,有什么帮助吗?

【问题讨论】:

请表定义。包括索引/键。没有聚合函数时为什么要分组? (SELECT DISTINCT 可能更快吗?) 请不要使用隐式连接。正确的连接是带有ON 子句的连接。 我刚刚用另一个有同样问题的查询更新了帖子,那就是正确的连接。我需要按 group by 分组的数据。 ¿ 表定义?键是所有表中的 id,现在也使用索引更新帖子。谢谢 这个 fecha_id 对我来说看起来像一个日期类型。为什么要将日期字段放入整数?并且:如果您对其进行大量(选择性)范围搜索,它可能需要一个索引。 添加了表定义和索引。 【参考方案1】:

试试这个

SELECT s.id as id, ht.count as menciones, bh.texto as hastag
FROM busquedas_hastag bh
INNER JOIN dashboards_hastag_tablaagregadatwitterdiaria ht ON ht.hastag_id=bh.id
INNER JOIN dashboards_tablaagregadatwitterdiaria s ON s.id=ht.tabla_id
INNER JOIN busquedas_busqueda bu ON s.busqueda_id=bu.id
WHERE bu.corporativa=false AND bu.cuenta_id=74
s.fecha_id >= 20150811 AND s.fecha_id <= 20150909
GROUP BY s.id, ht.count, hastag

如果您对此解决方案有任何问题,请告诉我

【讨论】:

以上是关于优化 PostgreSQL 中的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

从 EF 为 PostGresql 生成的查询中的非最佳计数

SQL语句优化,使用postgresql数据库,查询下面sql,需要20多分钟:

PostgreSQL 中的优化查询

从 PostgreSQL 中的字段中提取数字

数据库查询优化器的艺术:原理解析与SQL性能优化

优化以下 postgreSQL 代码的可能方法是啥?