LINUX.ORG.RU

Сообщения polin11

 

Написать тригерную функцию

Использую PGSQL, нyужно написать тригерную функцию: при удалении записи из таблицы Document нужно обновить\удалить запись из DocumentRaw. Нужно обновить json из DocumentRaw, если поле NewKey пустое у записи, то запись нужно удалить.

Написал такой вариант, но тут 3 действия: select, update, delete хочется сделать в 2 действия, select + (update либо delete в зависимости от условия) может это сделать через CASE


IF (OLD."Pk_Id" IS NOT NULL)
    THEN
        WITH rec AS(
            SELECT "@Document" AS "Id",
                    (COALESCE(("Key"->>OLD."Key"::text)::bigint, 0) - 1)::bigint AS "Value",
                    "Key"  - OLD."Key"::text AS "NewKey"
            FROM "Document"
            WHERE "Pk_Id" = OLD."Pk_Id"
            LIMIT 1
        ),
		  upd AS(
           UPDATE "DocumentRaw"
           SET "Key" =  (CASE
             WHEN (SELECT "Value" FROM rec) > 0 AND rec."NewKey" != '{}'::jsonb
             THEN "Key" || jsonb_build_object(OLD."Key"::text, (SELECT "Value" FROM rec))
             WHEN (SELECT "Value" FROM rec) <= 0 AND rec."NewKey" != '{}'::jsonb
             THEN "Key"  - OLD."Key"::text
             END
             )
           FROM rec
           WHERE
               rec."NewKey" != '{}'::jsonb AND
              "@DocumentRaw" = rec."Id"
       )
		 DELETE FROM "DocumentRaw"
       USING rec
       WHERE rec."NewKey" = '{}'::jsonb AND
       "@DocumentRaw" = rec."Id";
END IF;

 ,

polin11
()

Написать странный запрос с update

Использую PGSQL, упрощенный запрос выглядит так

 
WITH a
         AS ( SELECT DISTINCT UNNEST(ARRAY['777', NULL]) "Ключ",
         UNNEST(ARRAY['111', '222']) "Знач"
         )
 update "Документы"
 set "Название" = "Название" || '_' || a."Знач"
 FROM a
 where "Id" IS NOT DISTINCT FROM  a."Ключ"
returning *
хочется переписать запрос для того чтобы попадать в индекс, отдельно для нулевых значений и не нулевых, такого типа
 
WITH a
         AS ( SELECT DISTINCT UNNEST(ARRAY['777', NULL]) "Ключ",
         UNNEST(ARRAY['333', '444']) "Знач"
         )
 update "Документы"
 set "Название" = "Название" || '_' || a."Знач"
 FROM a
 where
   EXISTS (
    SELECT TRUE
    FROM a
    WHERE "Id" = a."Ключ" and "Id" IS NOT NULL and a."Ключ" IS NOT NULL  
    UNION
     SELECT TRUE
    FROM a
    WHERE "Id" IS NULL and a."Ключ" IS NULL
   )
returning *
этот запрос неверно определяет Знач, для своего Ключа. Как написать подобный запрос, если не прибегать к CTE?

 ,

polin11
()

Поэлементное сложение списков с вложенными словарями

Есть 2 списка всегда из 5 элементов - словарей, значения которых тоже словарь например

x = [{'2': {'1': 7}, '3':{'1':0, '5': 0}}, {}, {}, {}, {}]
y = [{'2': {'1': 1, '2': 5}}, {}, {}, {}, {}]
в итоге нужно сложить поэлементно два этих списка Должно получиться
x + y =   [{'2': {'1': 8, '2': 5}, '3':{'1':0, '5': 0}}, {}, {}, {}, {}]
начал писать запутался в циклах, просьба помочь

 ,

polin11
()

Ускорить простой запрос с CTE

Использую PGSQL, есть простой запрос,

	
	EXPLAIN (ANALYZE,BUFFERS)
	WITH data_to_cte AS (
		SELECT
			unnest[1]::integer account
		,	unnest[2]::text user_id
		,	unnest[3]::integer target_id
		FROM
			(
				SELECT
					unnest('{ "{ 7267996,4,96394594 }" }'::text[])::text[]
			) f
	)
	SELECT
		"DocumentsId",
		data_to_cte.*
	FROM
		data_to_cte
	JOIN
		"Documents"
			on "Account" = account AND 
			"Target" = target_id and
			"User" = user_id  AND
			"User" IS NOT NULL
план такой

Nested Loop  (cost=0.58..8.68 rows=1 width=48) (actual time=23.352..23.353 rows=0 loops=1)
  Buffers: shared hit=16730
  ->  Result  (cost=0.00..0.04 rows=1 width=32) (actual time=0.008..0.012 rows=1 loops=1)
        ->  ProjectSet  (cost=0.00..0.02 rows=1 width=32) (actual time=0.004..0.007 rows=1 loops=1)
              ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.002..0.002 rows=1 loops=1)
  ->  Index Scan using "iDocuments-AccountUser" on "Documents"  (cost=0.58..8.61 rows=1 width=28) (actual time=23.334..23.334 rows=0 loops=1)
        Index Cond: (("Account" = (((((unnest('{"{ 7267996,4,96394594 }"}'::text[])))::text[]))[1])::integer) AND ("User" = ((((unnest('{"{ 7267996,4,96394594 }"}'::text[])))::text[]))[2]))
        Filter: ((((((unnest('{"{ 7267996,4,96394594 }"}'::text[])))::text[]))[3])::integer = "Target")
        Rows Removed by Filter: 19163
        Buffers: shared hit=16730
Planning Time: 0.318 ms
Execution Time: 23.397 ms

Хочется чтобы использовался такой индекс

CREATE INDEX "iDocuments-AccountTarget"
	ON "Documents" USING btree
	("Account" NULLS LAST, "Target" NULLS LAST, "User" NULLS LAST)
	WHERE ("User" IS NOT NULL);
Что нужно сделать, возможно переписать запрос?

Например, если указать напрямую Target, то используется нужный индекс

	EXPLAIN (ANALYZE,BUFFERS)
	WITH data_to_cte AS (
		SELECT
			unnest[1]::integer account
		,	unnest[2]::text user_id
		,	unnest[3]::integer target_id
		FROM
			(
				SELECT
					unnest('{ "{ 7267996,4,96394594 }" }'::text[])::text[]
			) f
	)
	SELECT
		"DocumentsId",
		data_to_cte.*
	FROM
		data_to_cte
	JOIN
		"Documents"
			on "Account" = account AND 
			"Target" = 4 and
			"User" = user_id  AND
			"User" IS NOT NULL

 ,

polin11
()

Работа со словарем древовидной структуры

Есть словарь вида:

{
	1: {'name': 'Земля', 'parent': None}, 
	2: {'name': 'Евразия': 'parent': 1},
	3: {'name': 'Китай': 'parent': 2}, 
	4: {'name': 'Пекин': 'parent': 3},
	5: {'name': 'Австралия': 'parent': 1},  
	6: {'name': 'Сидней': 'parent': 5}
}

Нужно по ключу элемента получить всех родителей, например для ключа 4 - нужно получить элементы Китай, Евразия, Земля для ключа 6 - нужно получить элементы Австралия, Земля

Погуглил нашел, что-то похожее с использованием treelib, хочется сделать без сторонних библиотек, с первого взгляда задача несложная

 , ,

polin11
()

Логика работы SELECT FOR UPDATE

Использую СУБД PGSQL.

Нужно получить мин. значение CreateDate из таблицы документ

SELECT MIN("CreateDate")
FROM "Document"

если минимальная дата < текущей в цикле вешается транзация и пересчитывается поле CreateDate, достаю записи таким запросом:

SELECT *
FROM "Document"
WHERE "CreateDate" < NOW()::DATE
ORDER BY "CreateDate"
LIMIT 10
FOR UPDATE SKIP LOCKED
Обновление записей
UPDATE "Document"
SET "CreateDate" = ...
...

Насколько понимаю логику работы SELECT FOR UPDATE SKIP LOCKED при паральленых вызовах будут взяты не заблокированные записи. Как понимаю проблема будет возникать при получении мин. значение CreateDate,

SELECT MIN("CreateDate")
FROM "Document"
 
заблокированные записи будут пропущены и актульное значение не получить. Подскажите пож-ста можно как-то исправить эту проблему?

 ,

polin11
()

Сделать 2 поля уникальными, для определённого значения одного из них.

Использую PGSQL. Есть таблица

CREATE TABLE forms (
    id serial PRIMARY KEY,
    account INT NOT NULL,
    author text,
    type INT NOT NULL
);
INSERT INTO  forms(account, author, type) VALUES 
(1, 'Иванов', 11),
(2, 'Сидоров', 11),
(3, 'Сергеев', 12)
Нужно сделать набор полей (account, type) уникальным только для type = 11. Например обе записи нельзя было бы вставить, так как type = 11
(1, 'Иванов', 11),
(1, 'Сидоров', 11)
а например, записи можно было обе вставить, так как type != 11.
(1, 'Иванов', 12),
(1, 'Сидоров', 12)

Как это можно сделать в PGSQL?

 , ,

polin11
()

Операции над массивами

Использую Postgresql

  1. Есть удобная операция конкатенация массива ||, но при такой операции могут быть будут элементов например array[1,2,3] || array[1,4] -> array[1,2,3,1,4] Вопрос как объединить 2 массива при этом убрать дубли элементов?

  2. Если ли операция или функция убрать из массива элементы другого массива, то есть array[1,2,3] - array[1,4] -> array[2,3]?

 ,

polin11
()

Создать текстовый столбец в csv файле

Нужно в создать csv файл, столбец заполнить кодами строками вида

'10000000000000000'
'10100000000000000'
и т.д.

Делаю так:

with open("1.csv", mode="w", encoding='cp1251') as w_file:
    file_writer = csv.writer(w_file, delimiter = ";", lineterminator="\r")
    file_writer.writerow(['10000000000000000'])
    file_writer.writerow(['10100000000000000'])
Файл создает нормально, но когда его открываешь в excel, он автоматом эти строки приводит к числовому формату, получается столбец такого вида:
1E+16
1.01E+16
При открытии в excel нет возможности указать текстовый формат столбца (как это сделано например в LibreOffice), а если сменить формат ячеек в уже открытом документе, то excel просто числа приводит к строкам 1E+16, 1.01E+16 - по факту ничего не меняется, желаемого столбца из
10000000000000000
10100000000000000
не получается.

1) Можно ли в python при создании csv файла задать формат ячейки, чтобы excel уже открывал как нужно?

2) Если первый вариант невозможен, можно ли настроить excel, чтобы при открытии документа не приводил текст к числам?

 ,

polin11
()

Получить значения всех атрибутов класса

Есть класс используемый для хранения констант

class DataUser:
    user_one = 'Иванов'
    user_two = 'Петров'
	:
	:
	:
нужно получить список всех значений его атрибутов, не хочется делать перечисления типа
[DataUser.user_one, DataUser.user_two....]
Есть возможность получить список атрибутов, а нужно значения как это сделать?
[arg for arg in dir(DataUser) if not arg.startswith('_')]
Это тоже не работает
[DataUser.arg for arg in dir(DataUser) if not arg.startswith('_')]

 ,

polin11
()

Оптимизировать запрос с array_replace

Есть таблица Responsible, столбец Documents (тип bigint) ид. документа, User(тип []text) - массив пользователей. Нужно при смене пользователя, обновить этого пользователя в массиве User.

Есть такой запрос

UPDATE
	"Responsible"
SET
	"User" = array_replace(
		"User"
	,	'Петров'::text
	,	'Иванов'::text
	)
WHERE
	"Documents" = ANY('{3}') AND
	array_position("User", 'Петров'::text) IS NOT NULL
Но он много потребляет shared hit.
Update on "Responsible"  (cost=0.43..99802.28 rows=154773 width=74) (actual time=179.690..179.691 rows=0 loops=1)
  Buffers: shared hit=136800
  ->  Index Scan using "iDocuments" on "Responsible"  (cost=0.43..99802.28 rows=154773 width=74) (actual time=179.688..179.688 rows=0 loops=1)
        Index Cond: ("Documents" = ANY ('{3}'::bigint[]))
        Filter: (array_position("User", 'Петров'::text) IS NOT NULL)
        Rows Removed by Filter: 149754
        Buffers: shared hit=136800

Используется индекс по Documents, хочется уменьшить потребление shared hit, нет мыслей как это сделать. Как-то переписать запрос или изменить индекс не получается

 

polin11
()

Удалить из массива элементы

Удалить из массива элементы

Использую СУБД Postgresql. Есть таблица вида:

CREATE TABLE docs (
   id int PRIMARY KEY,
   account bigint,
   contact TEXT []
);
INSERT INTO docs VALUES(1, 22, ARRAY ['Иван', 'Петр']);
INSERT INTO docs VALUES(2, 22, ARRAY ['Иван']);
INSERT INTO docs VALUES(3, 22, ARRAY['Иван', 'Виктор']);
INSERT INTO docs values(4, 22, ARRAY['Иван', 'Роман', 'Сергей']);
Есть массив строк контактов(например ['Иван', 'Петр']) и аккаунт, нужно из поля contact удалить этих пользователей. Если после этого массив пустой, то нужно удалить запись целиком. Например из набора:
1, 22, ARRAY ['Иван', 'Петр']
2, 22, ARRAY ['Иван', 'Петр']
3, 22, ARRAY['Иван', 'Виктор']
4, 22, ARRAY['Иван', 'Роман', 'Сергей']
После обновления таблица должна иметь вида:
3, 22, ARRAY['Виктор']
4, 22, ARRAY['Роман', 'Сергей']
Просьба помочь это сделать одним запросом

 ,

polin11
()

Убрать из плана seq scan

Использую СУБД PGSQL. Есть таблица Documents в ней поле Account - целое, User - массив строк.

Происходит удаление пользователя, нужно этого пользователя удалить из User, если после удаления массив пустой, то нужно удалить запись. Написал такой запрос, но он стал жутко тормозить.

 WITH user AS (
                SELECT DISTINCT UNNEST(ARRAY['27672','6145']) AS "Id"
          ),
          ar AS(
                SELECT
                "@Id" AS "Id",
                  array_remove("User", user."Id") AS "NewUser",
                CASE
                      WHEN array_length(array_remove("User", user."Id"), 1) > 0 THEN FALSE
                      ELSE TRUE
                END AS "NeedDelete"
                FROM "Documents" ar, user
                WHERE
                      "Account" = 4777912 AND
                      array_position(ar."User", user."Id") IS NOT NULL
          ),
          delete_ar AS(
                DELETE FROM "Documents"
                USING ar
                WHERE "@Id" = ar."Id" AND
                      ar."NeedDelete" IS TRUE
          )
          UPDATE "Documents"
          SET "User" = ar."NewUser"
          FROM ar
          WHERE ar."Id" = "@Id" AND
               ar."NeedDelete" IS FALSE
			   
Update on "Documents"  (cost=19771027.17..22312135.48 rows=2074177 width=134) (actual time=188992.755..188992.755 rows=0 loops=1)
  Buffers: shared hit=22742 read=2790563 dirtied=121272 written=56091, temp read=8246 written=1402207
  CTE user
    ->  HashAggregate  (cost=0.02..0.52 rows=100 width=32) (actual time=0.007..0.010 rows=2 loops=1)
          Group Key: unnest('{27672,6145}'::text[])
          ->  Result  (cost=0.00..0.01 rows=1 width=32) (actual time=0.003..0.004 rows=2 loops=1)
  CTE ar
    ->  Nested Loop  (cost=0.57..237640.03 rows=4148354 width=37) (actual time=59.829..484.828 rows=44 loops=1)
          Join Filter: (array_position(ar_1."User", user."Id") IS NOT NULL)
          Rows Removed by Join Filter: 24234
          Buffers: shared hit=7660 read=1433 dirtied=13
          ->  CTE Scan on user  (cost=0.00..2.00 rows=100 width=32) (actual time=0.008..0.015 rows=2 loops=1)
          ->  Materialize  (cost=0.57..133720.72 rows=41692 width=35) (actual time=0.649..236.659 rows=12139 loops=2)
                Buffers: shared hit=7660 read=1433 dirtied=13
                ->  Index Scan using "iDocuments-AccountDocument" on "Documents" ar_1  (cost=0.57..133512.26 rows=41692 width=35) (actual time=1.296..466.032 rows=12139 loops=1)
                      Index Cond: ("Account" = '4777912'::bigint)
                      Buffers: shared hit=7660 read=1433 dirtied=13
  CTE delete_ar
    ->  Delete on "Documents" "Documents_1"  (cost=8512344.15..10206749.46 rows=2074177 width=34) (actual time=148112.808..148112.808 rows=0 loops=1)
          Buffers: shared hit=3422 read=2800776 dirtied=29, temp read=59703 written=801388
          ->  Hash Join  (cost=8512344.15..10206749.46 rows=2074177 width=34) (actual time=143942.901..148111.006 rows=38 loops=1)
                Hash Cond: (ar_2."Id" = "Documents_1"."@Id")
                Buffers: shared hit=3388 read=2800772 dirtied=3, temp read=59703 written=801388
                ->  CTE Scan on ar ar_2  (cost=0.00..82967.08 rows=2074177 width=32) (actual time=0.030..0.104 rows=38 loops=1)
                      Filter: ("NeedDelete" IS TRUE)
                      Rows Removed by Filter: 6
                ->  Hash  (cost=4888739.29..4888739.29 rows=208459029 width=10) (actual time=143820.738..143820.738 rows=205483044 loops=1)
                      Buckets: 1048576  Batches: 512  Memory Usage: 25459kB
                      Buffers: shared hit=3388 read=2800772 dirtied=3, temp written=800839
                      ->  Seq Scan on "Documents" "Documents_1"  (cost=0.00..4888739.29 rows=208459029 width=10) (actual time=0.040..85509.087 rows=205483044 loops=1)
                            Buffers: shared hit=3388 read=2800772 dirtied=3
  ->  Hash Join  (cost=9326637.15..11867745.46 rows=2074177 width=134) (actual time=187388.784..188988.878 rows=6 loops=1)
        Hash Cond: (ar."Id" = "Documents"."@Id")
        Buffers: shared hit=22689 read=2790553 dirtied=121259 written=56091, temp read=8246 written=1402207
        ->  CTE Scan on ar  (cost=0.00..82967.08 rows=2074177 width=96) (actual time=297.173..484.991 rows=6 loops=1)
              Filter: ("NeedDelete" IS FALSE)
              Rows Removed by Filter: 38
              Buffers: shared hit=7660 read=1433 dirtied=13
        ->  Hash  (cost=4888739.29..4888739.29 rows=208459029 width=42) (actual time=186809.680..186809.680 rows=205483044 loops=1)
              Buckets: 524288  Batches: 1024  Memory Usage: 17420kB
              Buffers: shared hit=15029 read=2789120 dirtied=121246 written=56091, temp written=1401178
              ->  Seq Scan on "Documents"  (cost=0.00..4888739.29 rows=208459029 width=42) (actual time=0.712..100785.196 rows=205483044 loops=1)
                    Buffers: shared hit=15029 read=2789120 dirtied=121246 written=56091			   

Хочется переписать запрос, чтобы не было seq scan, а использовался индекс @Id из Documents при удалении и обновлении записей

 

polin11
()

Ускорить простой запрос

Ускорить простой запрос нужно проверить входят ли ид. записей из массива в таблицу

SELECT ARRAY(
 SELECT  DISTINCT "Event"
        FROM "Documents"
        WHERE "Event" = ANY(ARRAY[1005657, 1005664, 7122])
        LIMIT 3
)

Для этого запроса такой план.

"Result  (cost=0.93..0.94 rows=1 width=32) (actual time=2.110..2.111 rows=1 loops=1)"
"  Buffers: shared hit=213"
"  InitPlan 1 (returns $0)"
"    ->  Limit  (cost=0.43..0.93 rows=3 width=4) (actual time=0.042..2.100 rows=3 loops=1)"
"          Buffers: shared hit=213"
"          ->  Unique  (cost=0.43..768.10 rows=4542 width=4) (actual time=0.040..2.096 rows=3 loops=1)"
"                Buffers: shared hit=213"
"                ->  Index Only Scan using "iEvent" on "Documents"  (cost=0.43..748.72 rows=7751 width=4) (actual time=0.039..1.532 rows=7709 loops=1)"
"                      Index Cond: ("Event" = ANY ('{1005657,1005664,7122}'::integer[]))"
"                      Heap Fetches: 72"
"                      Buffers: shared hit=213"
"Planning time: 0.510 ms"
"Execution time: 2.149 ms"

Проблема такая, что для ид. 7122 в таблице «Documents» существует записей 7709, достаем эти все записи. Хотелось бы переписать запрос, чтобы не все записи вытаскивали, а только до первой существующей.

 

polin11
()

Замена в jsonb значения

Использую POSTGRESQL, есть таблица с полем jsonb

select *
from 
(
values
(1, '{"name":["Иванов","Сидоров"], "town":"Paris"}'::jsonb),
(2, '{"name":["Иванов","Сергеев"], "town":"Berlin"}'::jsonb),
(3, '{"name":["Марков"], "town":"Rome"}'::jsonb)
) as q (id, data)
https://www.db-fiddle.com/f/dMK5uHZ8Thxnk57hi7f4wN/0

Нужно в массиве по ключу name заменить Иванов на Петров, в итоге, чтобы получилось

1	{"name":["Петров","Сидоров"],"town":"Paris"}
2	{"name":["Петров","Сергеев"],"town":"Berlin"}
3	{"name":["Марков"],"town":"Rome"}
Моих знаний хватило только, для разбиения на массив фамилий и ид. записей
select id, jsonb_array_elements(data->'name')
from 
(
values
(1, '{"name":["Иванов","Сидоров"], "town":"Paris"}'::jsonb),
(2, '{"name":["Иванов","Сергеев"], "town":"Berlin"}'::jsonb),
(3, '{"name":["Марков"], "town":"Rome"}'::jsonb)
) as q (id, data)
Просьба помочь написать запрос

 ,

polin11
()

Ошибка canceling statement due to statement timeout

Использую PGSQL. Есть таблица записей ~ 1000 000 записей

CREATE TABLE forms (
    id serial PRIMARY KEY,
    account INT NOT NULL,
    author text,
    salary INT NOT NULL
);
INSERT INTO  forms(account, author, salary) VALUES 
(1100889, 'Иванов', 30),
(1100889, 'Петров', 40),
(4443, 'Сидоров', 40),
(1100889, 'Сергеев', 50)

При авторизации пользователя в аккаунт идет пересчет поля salary в целом по аккаунту для всех пользователей

UPDATE forms
SET salary = (SELECT....)
WHERE account = 1100889
Перед обновление делаю блокировку по аккаунту с таймаутом 5 секунд.
BEGIN ISOLATION LEVEL READ COMMITTED READ WRITE;
SET LOCAL statement_timeout = '5000ms'; 
SELECT PG_ADVISORY_XACT_LOCK("lock_id") FROM (
                SELECT UNNEST('{1100889}'::BIGINT[]) AS "lock_id"
            ) LocksId      
RESET statement_timeout
В процессе обновления могут выполнятся обновления по конкретному сотруднику из этого аккаунта, я также ставлю блокировку по аккаунту.
UPDATE forms
SET salary = 100
WHERE account = 1100889 AND author = 'Иванов'
Когда общий запрос обновления по аккаунту (большой аккаунт) выполняется долго > 5 секунд, то падает ошибка на второй запрос обновления по сотруднику ошибка canceling statement due to statement timeout. Понятно, что оптимальное решение ускорить запрос расчета целиком по аккаунту.

Плохо разбираюсь в тебе блокировок в PGSQL, просьба подсказать как исправить ситуацию с точки зрения блокировок, в какую сторону смотреть?

Перемещено hobbit из general

 ,

polin11
()

Ошибка Memory Error

Есть метод для формирования архива из txt файлов. Список self.file_list может состоять из 300 файлов каждый файл по 512кб

def _create_archive(self):
        bt = BytesIO()
        zip = zipfile.ZipFile(bt, 'w', zipfile.ZIP_DEFLATED)
        for item in self.file_list:
            zip.writestr('{}.txt'.format(str(item.Name())), item.Data())
        zip.close()
        bt.seek(0)
        resulting_file = ResultingFile()
        resulting_file.SetName('ARCHIVE_NAME')
        resulting_file.SetData(bt.getvalue())
        bt.close()
        return resulting_file

При формировании этого архива в строке resulting_file.SetData(bt.getvalue()) падает через раз ошибка Memory Error, ResultingFile:SetData: Unable to write content of vector to ResultingFile. Есть какие-нибудь советы по оптимизации кода формирования архива?

 ,

polin11
()

Отсортировать сложный словарь на python

Есть словарь вида

{1:{'name': 'Иванов', 'salary': 5000}, 2:{'name': 'Алексеев', 'salary': 4000}, 3:{'name': 'Громов', 'salary': 3000}}

Нужно отсортировать по name, в итоге получить такой словарь

{2:{'name': 'Алексеев', 'salary': 4000}, 3:{'name': 'Громов', 'salary': 3000}, 1:{'name': 'Иванов', 'salary': 5000}}

Так как словарь может быть большой по размеру желательно использовать оптимальный способ сортировки

 ,

polin11
()

Оптимизировать запрос, доработать индекс

Использую POSTGRESQL. Есть запрос

EXPLAIN (ANALYZE, BUFFERS)
          SELECT
                        "Event",
                        NULL AS "User",
                        array_agg(DISTINCT "Subscriber") AS "Subscribers",
                        "Account" 
                    FROM "Document"                   
                    WHERE
                        "Account" = 3::bigint AND
                        "Event" IN (
                            SELECT
                               "@Event"
                            FROM "Event"
                            WHERE "Account" IS NULL
                        )
                        AND "User" IS NULL 
                        AND "Responsible" IS  TRUE
 
                    GROUP BY "Account", "Event"
План такой
"GroupAggregate  (cost=316074.96..317101.63 rows=45630 width=76) (actual time=873.803..1937.239 rows=614 loops=1)"
"  Group Key: "Document"."Account", "Document"."Event""
"  Buffers: shared hit=56295, temp read=3000 written=3020"
"  ->  Sort  (cost=316074.96..316189.03 rows=45630 width=17) (actual time=873.780..917.966 rows=325330 loops=1)"
"        Sort Key: "Document"."Event""
"        Sort Method: external merge  Disk: 11064kB"
"        Buffers: shared hit=56295, temp read=3000 written=3020"
"        ->  Hash Join  (cost=18182.35..311605.72 rows=45630 width=17) (actual time=50.095..709.771 rows=325330 loops=1)"
"              Hash Cond: ("Document"."Event" = "Event"."@Event")"
"              Buffers: shared hit=56295"
"              ->  Bitmap Heap Scan on "Document"  (cost=15425.55..307597.03 rows=476856 width=17) (actual time=35.353..623.525 rows=328867 loops=1)"
"                    Recheck Cond: (("Account" = '3'::bigint) AND ("User" IS NULL))"
"                    Rows Removed by Index Recheck: 3186345"
"                    Filter: ("Responsible" IS TRUE)"
"                    Rows Removed by Filter: 29341"
"                    Heap Blocks: exact=13476 lossy=38581"
"                    Buffers: shared hit=53938"
"                    ->  Bitmap Index Scan on "iUserNull"  (cost=0.00..15306.33 rows=491436 width=0) (actual time=32.748..32.748 rows=358208 loops=1)"
"                          Index Cond: ("Account" = '3'::bigint)"
"                          Buffers: shared hit=1881"
"              ->  Hash  (cost=2714.09..2714.09 rows=3417 width=4) (actual time=14.724..14.724 rows=3430 loops=1)"
"                    Buckets: 4096  Batches: 1  Memory Usage: 153kB"
"                    Buffers: shared hit=2357"
"                    ->  Seq Scan on "Event"  (cost=0.00..2714.09 rows=3417 width=4) (actual time=0.017..14.156 rows=3430 loops=1)"
"                          Filter: ("Account" IS NULL)"
"                          Rows Removed by Filter: 32279"
"                          Buffers: shared hit=2357"
"Planning time: 0.440 ms"
"Execution time: 1940.103 ms"
Проблема с условием с «Responsible» IS TRUE. Без этого условие план намного лучше
EXPLAIN (ANALYZE, BUFFERS)
          SELECT
                        "Event",
                        NULL AS "User",
                        array_agg(DISTINCT "Subscriber") AS "Subscribers",
                        "Account" 
                    FROM "Document"                   
                    WHERE
                        "Account" = 3::bigint AND
                        "Event" IN (
                            SELECT
                               "@Event"
                            FROM "Event"
                            WHERE "Account" IS NULL
                        )
                        AND "User" IS NULL 
                    GROUP BY "Account", "Event"
План такой:
"GroupAggregate  (cost=2915.22..63175.65 rows=47026 width=76) (actual time=17.555..377.618 rows=640 loops=1)"
"  Group Key: "Document"."Account", "Document"."Event""
"  Buffers: shared hit=208932"
"  ->  Merge Join  (cost=2915.22..62235.13 rows=47026 width=17) (actual time=17.533..169.674 rows=354287 loops=1)"
"        Merge Cond: ("Document"."Event" = "Event"."@Event")"
"        Buffers: shared hit=208932"
"        ->  Index Only Scan using "iUserNull" on "Document"  (cost=0.56..57605.15 rows=491436 width=17) (actual time=0.033..100.849 rows=358216 loops=1)"
"              Index Cond: ("Account" = '3'::bigint)"
"              Heap Fetches: 34720"
"              Buffers: shared hit=206575"
"        ->  Sort  (cost=2914.64..2923.19 rows=3417 width=4) (actual time=17.488..17.935 rows=3430 loops=1)"
"              Sort Key: "Event"."@Event""
"              Sort Method: quicksort  Memory: 257kB"
"              Buffers: shared hit=2357"
"              ->  Seq Scan on "Event"  (cost=0.00..2714.09 rows=3417 width=4) (actual time=0.019..16.530 rows=3430 loops=1)"
"                    Filter: ("Account" IS NULL)"
"                    Rows Removed by Filter: 32316"
"                    Buffers: shared hit=2357"
"Planning time: 0.433 ms"
"Execution time: 377.877 ms"

Предположительно нужно доработать индекс iUserNull, добавить предикат или поле «Responsible» IS TRUE, но это не хочется делать так как такое условие достаточно редкое.

Может есть другие варианты?

 

polin11
()

Использовать to_tsquery для поиска

Есть строка поиска, хочется сделать полнотекстовой поиск.

to_tsvector(‘simple’::regconfig, «Название») @@ to_tsquery(‘simple’::regconfig, ‘Мое_название’) AND «Название» IS NOT NULL

Но чтобы он работал, нужно удалить невалидные символы из строки поиска (например пробелы из строки поиска), нет ли команды из PGSQL, которая готовит строку для полнотекстового поиска?

 

polin11
()

RSS подписка на новые темы