Конференция "Базы" » Delphi + Postgresql. Нужен совет по оптимизации запросов
 
  • cr@nk © (15.06.14 13:03) [0]
    Доброго времени суток.
    Вопрос, скорее всего касается не конкретно PostgreSQL.
    Условно в БД у таблицы такая структура: Счётчик, Артикул, Наименование
    Приложение каждый день парсит файлы Excel и заносит инфу в БД. На каждую запись из файла excel приходятся следующие проверки:
    Считали строку (несколько ячеек) в переменные
    Формируем запрос на поиск совпадения АРтикулИзФайла и АртикулИзБазы
    Если совпадений нет, то добавляем запись
    Если найдено одно совпадение, то происходит проверка НаименованиеИзФайла и НаиманованиеИзБазы. Если есть различия, то вызывается UPDATE
    Несмотря на все индексы программа работает со средней скоростью.

    Хотелось узнать можно ли как-то ускорить этот процесс? Какие-нибудь триггеры или хранимые процедуры или ещё что-то...
  • Ega23 © (15.06.14 13:31) [1]

    > Хотелось узнать можно ли как-то ускорить этот процесс?


    Да.


    > Какие-нибудь триггеры или хранимые процедуры


    Да.
  • cr@nk © (15.06.14 14:33) [2]
    Может быть подскажете на каком-то примере?
    Сам не могу чётко сформулировать запрос для гугла :(
    Или хотя бы на словах о том, как это реализовать
  • sniknik © (15.06.14 15:50) [3]
    > Может быть подскажете на каком-то примере?
    на каком? оптимизировать запрос можно только существующий. нельзя оптимизировать то чего нет.
    +, запрос, в связке Excel-Delphi-PostgreSQL очевидно не самое медленное.

    > Или хотя бы на словах о том, как это реализовать
    выкинуть Excel, формат входного файла привести к чему нибудь, что PostgreSQL "понимает" и может обрабатывать списком (ну например, возможно, csv), запросы использовать соответственно "пакетные", и желательно одновременной вставки/апдейте (типа в mssql megre, в mysql insert с on duplicate key update)
  • cr@nk © (15.06.14 16:28) [4]

    > на каком? оптимизировать запрос можно только существующий

    Тут имел ввиду пример на триггер или хранимую процедуру (смотря, что имел ввиду Ega23). Даже не пример, а описать вкратце, что писать в триггере/хранимой процедуре


    > выкинуть Excel

    Эх, ну выкинуть не получится. Разве, что преобразовывать все Excel в CSV . Но это тоже придётся делать программно. И не факт, что будет прирост в скорости

    Ну и я сам виноват - не полностью обрисовал ситуацию. Строка из файла Excel разносится по двум таблицам (связанным один-ко-многим)
    Если это поможет решению вопроса, то вот общая структура БД

    CREATE TABLE resource
    (
     id serial NOT NULL,
     article text,
     name text,
     fav boolean DEFAULT false,
     CONSTRAINT resource_pkey PRIMARY KEY (id)
    )


    CREATE TABLE resource_d
    (
     id serial NOT NULL,
     id_article integer,
     pricedate date,
     cost text,
     CONSTRAINT resource_d_pkey PRIMARY KEY (id)
    )

  • turbouser © (15.06.14 16:32) [5]

    > cr@nk ©

    Загрузка как происходит? insert - commit?
  • turbouser © (15.06.14 16:36) [6]
    хотя, судя по всему именно так. тогда можно посоветовать пакетную загрузку, типа commit только после 100 (500,1000, etc) insert
  • sniknik © (15.06.14 17:03) [7]
    > Тут имел ввиду пример на триггер или хранимую процедуру (смотря, что имел ввиду Ega23). Даже не пример, а описать вкратце, что писать в триггере/хранимой процедуре
    ну, если все так просто ...
    https://www.google.ru/search?q=пример+на+триггер+или+хранимую+процедуру

    > смотря, что имел ввиду Ega23
    думаешь он без знаний твоей специфики обладает по ней какими-то тайными знаниями?

    > И не факт, что будет прирост в скорости
    само собой не факт, смотря как сейчас сделано, и как сделать преобразование... если сейчас "поячеечно" а сделать "пакетом" то наверняка буде.
  • cr@nk © (15.06.14 18:04) [8]

    > хотя, судя по всему именно так. тогда можно посоветовать
    > пакетную загрузку, типа commit только после 100 (500,1000,
    >  etc) insert

    Про пакетную загрузку вроде осознал (что происходит с записями, если он существуют буду разбираться позже)
    Сейчас не могу понять, как это сделать для двух связанных таблиц (связаны по полям id serial -> id article)
  • cr@nk © (15.06.14 18:36) [9]
    uqAdd.SQL.Text := 'INSERT INTO ' + tname + ' (Article, Name) VALUES (:Article, :Name) RETURNING *;';

    передаются параметры и получаю
    IDArt := FieldByName('ID').AsInteger;

    uqAddCost.SQL.Text := 'INSERT INTO ' + tname + '_d' + ' (PriceDate, ID_Article, Cost) VALUES (:PriceDate, :IDArticle, :Cost)';

    Вот такими запросами добавляются данные в 2 связанные таблицы
  • Ega23 © (15.06.14 20:44) [10]
    Надо либо хранимку написать. Либо триггер. Либо что-то подобное http://www.postgresql.org/docs/9.3/static/rules-update.html
    В старом MSSQL на обработке исключения сделал. Ну, типа
    try
     insert into ttt
    catch
     update ttt

    Это на порядок быстрее, чем сначала проверять на наличие.
    Для Postgres, вроде бы, есть конструкция "insert or update". Но не уверен, дело давно было.
    Ну и, самое главное, возьми и замеряй:
    1. Время обработки входного Excel-файла
    2. Время передачи данных
    3. Время обработки данных на сервере.
    Так будешь, по крайней мере, знать "узкое место" .


    > uqAdd.SQL.Text := 'INSERT INTO ' + tname + ' (Article, Name)
    > VALUES (:Article, :Name) RETURNING *;';


    > uqAddCost.SQL.Text := 'INSERT INTO ' + tname + '_d' + '
    > (PriceDate, ID_Article, Cost) VALUES (:PriceDate, :IDArticle,
    >  :Cost)';


    Я надеюсь, что это дело задаётся один раз, а не каждый? И всем Prepare в True выставлено?
  • cr@nk © (15.06.14 22:49) [11]

    >
    > Я надеюсь, что это дело задаётся один раз, а не каждый?
    > И всем Prepare в True выставлено?

    Угу :)

    > Для Postgres, вроде бы, есть конструкция "insert or update"

    Отлично. Вроде есть такая конструкция. Попробую применить на практике
  • Sergey13 © (16.06.14 09:04) [12]
    Можно, как вариант, все без разбору залить в отдельную таблицу, а уже потом....
  • cr@nk © (16.06.14 17:07) [13]

    > Можно, как вариант, все без разбору залить в отдельную таблицу,
    >  а уже потом....
    >

    Вы договаривайте, не стесняйтесь :)
    Записать данные из файла во временную таблицу? А что потом?

    Я как раз сейчас начинаю пересматривать структуру БД. Вдруг чего дельного из вашего совета вынесу =)

    Есть ещё абстрактный вопрос по скорости: Сейчас у меня используется примерно 15 пар таблиц вида ИмяТаблиы1 + ИмяТаблицы1_d
    Поиск по всем таблицам реализован через union
    Если слить все таблицы в одну (добавив поле, позволяющее идентифицировать таблицу, откуда была слита информация) то будет ли какой либо прирост по скорости поиска данных?
  • turbouser © (16.06.14 17:23) [14]
    postgres поддерживает external tables, так что можно воспользоваться
    http://www.postgresql.org/docs/9.1/static/ddl-foreign-data.html
  • turbouser © (16.06.14 17:29) [15]
    Да и XML поддерживает
    http://www.postgresql.org/docs/devel/static/functions-xml.html
    так что можно на клиенте формировать из порции данных XML и передавать в ХП, а там парсить и insert/update
  • Inovet © (16.06.14 17:48) [16]
    > [13] cr@nk ©   (16.06.14 17:07)

    И зачем их было в 15 пар засовывать, если эти данные по суди однотипные. Вряд ли на итоговых юнионах индексы будут хорошо работать, если они хоть как-то работают. А они вообще есть?
  • sniknik © (16.06.14 17:51) [17]
    > Вы договаривайте, не стесняйтесь :)
    в зеркало посмотри. повтори.

    > Есть ещё абстрактный вопрос по скорости:
    на абстрактный вопрос аналогичный ответ - а хрен его знает. все зависит от реализации, как сделано, как сделаешь... но, похоже повторяюсь.

    ничего абстрактно не оптимизируется. блин опять повторяюсь.

    единственный значимый совет (всякие там "парси так/это", или "парси тут" не работают в отрыве от конкретики, а ее от тебя 0) это делать все "пакетно", обработка команды в 1 запись и в 100 (... +- сколько то) записей по времени практически одинаковы.

    > то будет ли какой либо прирост по скорости поиска данных?
    а если я почешу себя левой пяткой за правым ухом зуд пройдет?

    > postgres поддерживает external tables
    он много чего поддерживает, например "копирование" из csv в 1 команду, но чем это поможет в "оптимизации запросов" автора топика?
  • MsGuns © (16.06.14 19:26) [18]
    Делал что-то похожее, только вместо делфи был сибилдер (но это, думаю, не существенно)
    Все работало медленно, пока не стал из Эксела грузить все в отдельную таблицу, а из нее ХП рассовывала по таблицам БД. Все эксепштны также писались в отд.таблицу, которя затем передавалась тому же экселу.

    Все стало летать.
  • turbouser © (16.06.14 20:54) [19]

    > sniknik ©   (16.06.14 17:51) [17]


    > он много чего поддерживает, например "копирование" из csv
    > в 1 команду, но чем это поможет в "оптимизации запросов"
    > автора топика?

    в "оптимизации запросов" не поможет, конечно, но ускорить загрузку - вполне.
  • Sergey13 © (17.06.14 09:27) [20]
    2cr@nk ©   (16.06.14 17:07) [13]
    >А что потом?
    Потом можно оперировать запросами сразу по всем данным. Типа одним запросом вставить все которых нет, а вторым проапдейтить все что есть. Ну, если не заморачиваться на специфические возможности сервера.

    >будет ли какой либо прирост по скорости поиска данных?
    По скорости - может будет прогресс, может нет, важна реализация. А вот длина текста запроса сократится в 15 раз - уже неплохо.8-)
 
Конференция "Базы" » Delphi + Postgresql. Нужен совет по оптимизации запросов
Есть новые Нет новых   [118593   +0][b:0][p:0.001]