【问题标题】:Slow sub-SELECT GROUP BY JPQL query慢子SELECT GROUP BY JPQL查询
【发布时间】:2018-09-07 16:18:09
【问题描述】:

针对 PG 9.6 执行以下 JPQL 大约需要 1.5 秒:

@Query(" SELECT t FROM T t WHERE t.id in ("
     + "   SELECT MAX(t.id) FROM T t, C c "
     + "     WHERE t.m           = :m     "
     + "       AND t.c           = c      "
     + "       AND c.createdDate < :date  "
     + "     GROUP BY t.m, t.p            "
     + "   )                              ")
List<T> tByDate(@Param("m") M m, @Param("date") LocalDateTime date);

有什么想法可以在不改变数据库模型的情况下加快速度吗?

Table T(大小 45k)

CREATE TABLE public.t 
(
  id bigint NOT NULL DEFAULT nextval('t_id_seq'::regclass),
  c_id bigint NOT NULL,
  m_id bigint NOT NULL,
  p_id bigint NOT NULL,
  CONSTRAINT t_pkey PRIMARY KEY (id),
  CONSTRAINT fkcdo362oanw5jshu29kavksyfy FOREIGN KEY (m_id)
    REFERENCES public.m (id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fkjpyqqd0vys4jayau98eij2xv3 FOREIGN KEY (c_id)
    REFERENCES public.c (id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fknjjuiq1kn44mu5299dn67t3np FOREIGN KEY (p_id)
    REFERENCES public.p (id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION
)

表 C(大小 45k)

CREATE TABLE public.c
(
  id bigint NOT NULL DEFAULT nextval('c_id_seq'::regclass),
  created_by character varying(255),
  created_date timestamp without time zone NOT NULL,
  m_id bigint,
  CONSTRAINT c_pkey PRIMARY KEY (id),
  CONSTRAINT fkbv33l9w17owvi5kgctqvaepn0 FOREIGN KEY (m_id)
    REFERENCES public.m (id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION
)

表 M(尺寸 200)

CREATE TABLE public.m
(
  id bigint NOT NULL DEFAULT nextval('m_id_seq'::regclass),
  created_by character varying(255),
  created_date timestamp without time zone NOT NULL,
  a_id bigint,
  CONSTRAINT m_pkey PRIMARY KEY (id),
  CONSTRAINT fkikqmae593j3mruwqy84pc56is FOREIGN KEY (a_id)
      REFERENCES public.a (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

表 P(大小 5k)

CREATE TABLE public.p
(
  id bigint NOT NULL,
  created_by character varying(255),
  created_date timestamp without time zone NOT NULL,
  e character varying(255) NOT NULL,
  a_id bigint,
  CONSTRAINT p_pkey PRIMARY KEY (id),
  CONSTRAINT fkehggtafv310ewdtcq772pwl01 FOREIGN KEY (a_id)
      REFERENCES public.a (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

【问题讨论】:

  • 试试这个:SELECT t FROM T t WHERE t.id in ( SELECT MAX(t.id) FROM T t outer join C c on (c.id = t.c_id) WHERE t.m = :m AND t.c = c AND c.createdDate &lt; :date GROUP BY t.m, t.p ) 我认为您需要在此查询中检查内部/外部联接,并且不要忘记传递加入字段。
  • @AleksandrsRudzitis -- 切换到 JOIN 不会提高性能。

标签: spring postgresql spring-data-jpa jpql


【解决方案1】:

This is a special case of the common "top N per category" problem,SQL 中有一些解决方案。为什么不直接使用原生 SQL?您的查询可以转化为:

SELECT (t).*
FROM (
  SELECT t, ROW_NUMBER() OVER (PARTITION BY t.m_id, t.p_id ORDER BY t.id DESC) rn
  FROM t
  JOIN c ON t.c_id = c.id
  WHERE t.m_id = :m
  AND c.created_date < :date
) t
WHERE t.rn = 1

主要区别在于您可以避免对T 表的一次访问。

当然,我假设您拥有所有适当的索引,包括所有外键和C.CREATED_DATE 列上的索引。结果仍然可以映射到实体。

注意,I'm using PostgreSQL specific syntax to nest records,这样再次从投影中删除 RN 列要容易得多。

【讨论】:

    猜你喜欢
    • 2015-10-23
    • 2013-05-30
    • 2020-08-15
    • 1970-01-01
    • 2021-11-17
    • 2016-05-01
    • 1970-01-01
    • 2021-04-18
    • 1970-01-01
    相关资源
    最近更新 更多