powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Вложенный запрос или агрегаты?
3 сообщений из 3, страница 1 из 1
Вложенный запрос или агрегаты?
    #39649225
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Имеется справочник привязки электронных кошельков к клиентам
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
CREATE TABLE cl_moneybags (
  CRId bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Идентификатор кошелька',
  ClientId bigint(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Код клиента', -- FK из справочника клиентов
  MoneybagId tinyint(3) UNSIGNED NOT NULL COMMENT 'Код кошелька', -- FK из справочника кошельков
  Checked tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Используется?',
  TotalMoneybagCountRemains decimal(10, 2) DEFAULT 0.00 COMMENT 'Остаток кол-во месячных лимитов',
  LocalMoneybagCountRemains decimal(10, 2) DEFAULT 0.00 COMMENT 'Остаток кол-во дневных лимитов',
  TotalMoneybagSumRemains decimal(10, 2) DEFAULT 0.00 COMMENT 'Остаток месячного лимита - сумма',
  LocalMoneybagSumRemains decimal(10, 2) DEFAULT 0.00 COMMENT 'Остаток дневного лимита - сумма',
  TotalMoneybagCountSpend decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT 'Потрачено в месяц кол-ва',
  LocalMoneybagCountSpend decimal(10, 2) DEFAULT 0.00 COMMENT 'Потрачено в день кол-ва',
  TotalMoneybagSumSpend decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT 'Потрачено в месяц суммы',
  LocalMoneybagSumSpend decimal(10, 2) DEFAULT 0.00 COMMENT 'Потрачено в день суммы',
  PRIMARY KEY (CRId),
  INDEX ClientId (ClientId),
  UNIQUE INDEX UK_ClientId_MoneybagId (ClientId, MoneybagId),
  CONSTRAINT FK_cl_moneybags_ref_Moneybags FOREIGN KEY (MoneybagId)
  REFERENCES ref_moneybags (MoneybagId) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT fk_client_moneybags_clients FOREIGN KEY (ClientId)
  REFERENCES cl_clients (ClientId) ON DELETE CASCADE ON UPDATE CASCADE
)
ENGINE = INNODB
CHARACTER SET cp1251
COLLATE cp1251_general_ci
COMMENT = 'Справочник кошельков клиентов';


(Кошельки могут быть как суммовые, так и количественные, поэтому все поля в двух экземплярах)

и таблица оплат
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
CREATE TABLE ch_item_moneybags (
  CIRId bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Идентификатор',
  ChekId bigint(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Код чека',
  NumPos int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '№ позиции',
  MoneybagId tinyint(3) UNSIGNED DEFAULT NULL COMMENT 'Код кошелька', -- FK из справочника кошельков
  IPSumCalc decimal(10, 2) DEFAULT NULL COMMENT 'Сумма оплаты',
  IPCount decimal(14, 6) DEFAULT NULL COMMENT 'Количество оплаты',
  PRIMARY KEY (CIRId),
  INDEX FK_item_payments_rations (MoneybagId),
  UNIQUE INDEX UK_ch_item_moneybags (ChekId, NumPos, MoneybagId),
  CONSTRAINT FK_ch_item_moneybags FOREIGN KEY (ChekId, NumPos)
  REFERENCES ch_chek_items (ChekId, NumPos) ON DELETE CASCADE ON UPDATE CASCADE
)
ENGINE = INNODB
CHARACTER SET cp1251
COLLATE cp1251_general_ci
COMMENT = 'Оплаты чека по позициям';



Каждая позиция чека может быть оплачена несколькими кошельками.
После заполнения таблицы оплат требуется пробежаться по всем ее строкам в пределах выбранного чека, посчитать сумму оплаты каждым кошельком и отредактировать все поля "Остаток" и "Потрачено". Сейчас это сделано так:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
UPDATE cl_moneybags ccr      
JOIN (SELECT      
    ip.MoneybagId,      
    SUM(ip.IPCount) AS MoneybagCount,      
    SUM(ip.IPSumCalc) AS MoneybagSum      
  FROM ch_item_moneybags ip      
  WHERE ip.ChekId = :ChekId      
  GROUP BY ip.MoneybagId) AS tmp2      
  ON tmp2.MoneybagId = ccr.MoneybagId      
SET ccr.TotalMoneybagCountRemains = ccr.TotalMoneybagCountRemains - tmp2.MoneybagCount,      
    ccr.TotalMoneybagSumRemains = ccr.TotalMoneybagSumRemains - tmp2.MoneybagSum,      
    ccr.LocalMoneybagCountRemains = ccr.LocalMoneybagCountRemains - tmp2.MoneybagCount,      
    ccr.LocalMoneybagSumRemains = ccr.LocalMoneybagSumRemains - tmp2.MoneybagSum,      
    ccr.TotalMoneybagCountSpend = ccr.TotalMoneybagCountSpend + tmp2.MoneybagCount,      
    ccr.TotalMoneybagSumSpend = ccr.TotalMoneybagSumSpend + tmp2.MoneybagSum,      
    ccr.LocalMoneybagCountSpend = ccr.LocalMoneybagCountSpend + tmp2.MoneybagCount,      
    ccr.LocalMoneybagSumSpend = ccr.LocalMoneybagSumSpend + tmp2.MoneybagSum      
WHERE ccr.ClientId = :ClientId; 



Оптимизатору эта конструкция не нравится, судя по строке <derived2>.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
==========================================================================================================================================================================================================
|id |select_type  |table       |type   |possible_keys                                     |key                    |key_len |ref                    |rows  |Extra                                         |
==========================================================================================================================================================================================================
|1  |PRIMARY      |<derived2>  |ALL    |null                                              |null                   |null    |null                   |2     |Using where                                   |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|1  |PRIMARY      |ccr         |eq_ref |UK_ClientId_MoneybagId,ClientId,FK_cl_moneybags_re|UK_ClientId_MoneybagId |9       |const,tmp2.MoneybagId  |1     |                                              |
|   |             |            |       |f_Moneybags                                       |                       |        |                       |      |                                              |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|2  |DERIVED      |ip          |ref    |UK_ch_item_moneybags                              |UK_ch_item_moneybags   |8       |const                  |1     |Using where; Using temporary; Using filesort  |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



Есть идея реализовать все это через агрегатные функции
Код: sql
1.
2.
3.
4.
5.
6.
7.
UPDATE cl_moneybags cm SET
  TotalMoneybagCountRemains = TotalMoneybagCountRemains - 
    (SELECT SUM(cim.IPCount) FROM ch_item_moneybags cim WHERE cim.ChekId = :ChekId AND cim.MoneybagId = cm.MoneybagId),
  TotalMoneybagSumRemains = TotalMoneybagSumRemains - 
    (SELECT SUM(cim.IPSumCalc) FROM ch_item_moneybags cim WHERE cim.ChekId = :ChekId AND cim.MoneybagId = cm.MoneybagId)
  -- аналогично для остальных полей
WHERE cm.ClientId = :ClientId


Но смущает тот факт, что вычисление сумм в этом случае будет выполняться 8 раз. Будет ли этот вариант оптимальнее?
...
Рейтинг: 0 / 0
Вложенный запрос или агрегаты?
    #39649290
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
A-MaRБудет ли этот вариант оптимальнее?
Не вижу смысла забивать себе голову производительностью ЭТОГО запроса. Посмотри в поле rows плана - ну хрена ли там ещё оптимизировать? индекс с префиксом ch_item_moneybags (ChekId) есть? индекс cl_moneybags(ClientId) есть? ну и достаточно...
...
Рейтинг: 0 / 0
Вложенный запрос или агрегаты?
    #39649302
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina,

Понял, спасибо.
...
Рейтинг: 0 / 0
3 сообщений из 3, страница 1 из 1
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Вложенный запрос или агрегаты?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]