Арифметика даты с использованием целочисленных значений - PullRequest
2 голосов
/ 11 июня 2010

Проблема

Конкатенация строк замедляет запрос:

date(extract(YEAR FROM m.taken)||'-1-1') d1,
date(extract(YEAR FROM m.taken)||'-1-31') d2

Это реализовано в коде как часть строки, которая следует (где переменные p_ являются целыми числами,предоставляется в качестве входных данных конечными пользователями):

date(extract(YEAR FROM m.taken)||''-'||p_month1||'-'||p_day1||''') d1,
date(extract(YEAR FROM m.taken)||''-'||p_month2||'-'||p_day2||''') d2

Эта часть запроса выполняется за 3,2 секунды с датами и 1,5 секунды без, что позволяет мне полагать, что для улучшения есть достаточно места.

Общее время выполнения запроса не превышает 10 секунд;Я хочу сократить весь запрос до 2 или 3 секунд.Аппаратное обновление уже произошло.; -)

Версия

PostgreSQL 8.4.4.

Вопрос

Как лучше создать дату (предположительно без объединения)?

Обновление

Это выглядит многообещающе: PGTYPESdate_mdyjul

Большое спасибо!

Ответы [ 3 ]

2 голосов
/ 11 июня 2010

К сожалению, я не думаю, что есть другой способ построить дату без объединения текстов.

Да, честно говоря, мне не нравится подход Postgresql здесь. Кажется, что большинство манипуляций с датами должно быть сделано путем извлечения полей даты как целых чисел, преобразования их в текст, добавления их к большему количеству текстов, чтобы создать текстовое представление даты, и затем сказать postgres для анализа этого текста как даты ... плохо для меня, я инстинктивно чувствую, что построение даты путем анализа строки должно быть сделано только из текстовых входных данных. Но, я думаю, postgresql слишком сильно связывает обработку типов данных с их текстовыми представлениями. И поэтому, например, если я хочу построить дату из трех целочисленных значений (D, M, Y), я ДОЛЖЕН (если я не ошибаюсь) построить строку и заставить PG разобрать ее. Я чувствую себя так нечисто, делая это ...

Отбросьте в сторону, я сомневаюсь, что это может сильно замедлить вашу производительность.

1 голос
/ 11 июня 2010

Ничего себе. Я удивлен, но использование функций из этой страницы - в частности, той, которая строит значение даты из трех целых чисел - которые на самом деле больше ничего не делают для раскрытия внутренних функций даты Си, действительно намного быстрее. Бенчмаркинг для меня показывает, что создание дат таким образом было намного быстрее.

Первый - реализация функции dateserial:

postgres=# select to_date(a,1,3) 
postgres-# from generate_series(100,1000000) as v(a);

Time: 1365.851 ms

postgres=# select (a::text||'-01-03')::date from 
postgres-# generate_series(100,1000000) as v(a);

Time: 3454.224 ms

Полное решение

Редактировать dateserial.c:

#include "postgres.h"
#include "utils/date.h"
#include "utils/nabstime.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

Datum dateserial(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1 (dateserial);

Datum
dateserial(PG_FUNCTION_ARGS) {
  int32 p_year = PG_GETARG_INT32(0);
  int32 p_month = PG_GETARG_INT32(1);
  int32 p_day = PG_GETARG_INT32(2);

  PG_RETURN_DATEADT( date2j( p_year, p_month, p_day ) - POSTGRES_EPOCH_JDATE );
}

Редактировать Makefile:

MODULES = dateserial
PGXS := $(shell pg_config --pgxs)
include $(PGXS)

Редактировать inst.sh (необязательно):

#!/bin/bash

make clean && make && strip *.so && make install && /etc/init.d/postgresql-8.4 restart

Выполнить bash inst.sh.

Создать функцию SQL dateserial:

CREATE OR REPLACE FUNCTION dateserial(integer, integer, integer)
  RETURNS date AS
'$libdir/dateserial', 'dateserial'
  LANGUAGE 'c' IMMUTABLE STRICT
  COST 1;
ALTER FUNCTION dateserial(integer, integer, integer) OWNER TO postgres;

Проверка функции:

SELECT dateserial( 2007::int, 5, 5 )
0 голосов
/ 11 июня 2010

Другой альтернативой может быть создание индекса функции для объединения.Это работает в более общих случаях, когда нет лучшего типа данных.

...