MariaDB: несколько SELECT COUNT(*)

Тема в разделе "Базы данных", создана пользователем pastuhoff, 11 авг 2014.

Модераторы: latteo
  1. pastuhoff

    pastuhoff Создатель

    Регистр.:
    11 июл 2012
    Сообщения:
    49
    Симпатии:
    6
    Коллеги, подскажите, можно ли на такой таблице

    CREATE TABLE `z` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    `x` smallint(5) unsigned NOT NULL DEFAULT '0',
    `a` int(11) unsigned NOT NULL DEFAULT '0',
    `b` int(11) unsigned NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    KEY `x` (`x`)
    ) ENGINE=Aria DEFAULT CHARSET=cp1251 PAGE_CHECKSUM=1 TRANSACTIONAL=0

    объединить запросы

    SELECT COUNT(*) AS n1 FROM `z` WHERE x=1
    SELECT COUNT(*) AS n2 FROM `z` WHERE a=0 AND x=1
    SELECT COUNT(*) AS n3 FROM `z` WHERE a=1 AND x=1
    SELECT COUNT(*) AS n4 FROM `z` WHERE a>1 AND x=1
    SELECT COUNT(*) AS n5 FROM `z` WHERE b=0 AND x=1
    SELECT COUNT(*) AS n6 FROM `z` WHERE b=1 AND x=1
    SELECT COUNT(*) AS n7 FROM `z` WHERE b>1 AND x=1

    в один, дабы уменьшить общее время выполнения всех этих селектов (новые индексы создавать нельзя).
     
  2. pastuhoff

    pastuhoff Создатель

    Регистр.:
    11 июл 2012
    Сообщения:
    49
    Симпатии:
    6
    Подсказали следующее решение:

    SELECT
    SUM(1) AS `n1`,
    SUM(IF(a=0,1,0)) AS `n2`,
    SUM(IF(a=1,1,0)) AS `n3`,
    SUM(IF(a>1,1,0)) AS `n4`,
    SUM(IF(b=0,1,0)) AS `n5`,
    SUM(IF(b=1,1,0)) AS `n6`,
    SUM(IF(b>1,1,0)) AS `n7`
    FROM `z` WHERE x=1

    Это ведь уже нельзя ускорить?
     
  3. Шумадан

    Шумадан Хабарра!!11

    Регистр.:
    6 фев 2008
    Сообщения:
    1.728
    Симпатии:
    2.105
    а нельзя ли сделать отдельную колонку где будут значения
    1 - WHERE x=1
    2 - WHERE a=0 AND x=1
    3 - WHERE a=1 AND x=1
    4 - WHERE a>1 AND x=1
    5 - WHERE b=0 AND x=1
    6 - WHERE b=1 AND x=1
    7 - WHERE b>1 AND x=1
    а потом выборка по этому полю, + индексирования
    апдейт поля при инсерте и апдейте таблички либо как значание передавать, либо триггер прицепить (есть в мускуле триггеры), либо кроном пересчитывать
     
    Джуга, Ctrogan, SilverGhost и ещё 1-му нравится это.
  4. pastuhoff

    pastuhoff Создатель

    Регистр.:
    11 июл 2012
    Сообщения:
    49
    Симпатии:
    6
    Благодарю. Ваш вариант непозволительно увеличит размер файлов базы и замедлит изменения параметров a и b (в реальности там еще аналогичные c,d,...).
    Приведенный вариант во втором посте в принципе устраивает. Разве что его можно как-то ускорить (не трогая триггеры, индексы, тип таблицы), изменив сам запрос на выборку на еще более хитроумный.
     
    Шумадан нравится это.
  5. Шумадан

    Шумадан Хабарра!!11

    Регистр.:
    6 фев 2008
    Сообщения:
    1.728
    Симпатии:
    2.105
    насколько непозволительно? в этом поле будет храниться минимум информации, тип поля вообще TINYINT скажем, это аж 1 байт :crazy:, сколько же записей в таблице у вас, чтоб этот 1 байт привёл к существенному увеличению? :smmne:

    а вообще, попробуйте оба варианта, желательно на 10К-1М записях и посмотрите внимательно план выполнения запроса :-]
    ну и последнее, даже если у вас там есть ещё c, d, e ... колонки, которые, кстате, нигде не видны в примере, подход с поле, где указано группу по которой суммировать опять же работает
     
    Последнее редактирование: 11 авг 2014
    Джуга, Ctrogan и SilverGhost нравится это.
  6. pastuhoff

    pastuhoff Создатель

    Регистр.:
    11 июл 2012
    Сообщения:
    49
    Симпатии:
    6
    Мне критично важно очень частое (~100% времени процессор загружен именно этим на ~100%) изменение полей a,b и т.д. Это нужно делать максимально быстро. Записей пока 600+ миллионов.
     
  7. NDK13

    NDK13 Создатель

    Регистр.:
    31 авг 2012
    Сообщения:
    36
    Симпатии:
    14
    А в чем проблема использовать UNION?
    Код:
    SELECT COUNT(*) AS n1 FROM `z` WHERE x=1
    UNION
    SELECT COUNT(*) AS n1 FROM `z` WHERE a=0 AND x=1
    
    только везде использовать "AS n1" а в программе выбирать значения по номеру строки результата
     
  8. pastuhoff

    pastuhoff Создатель

    Регистр.:
    11 июл 2012
    Сообщения:
    49
    Симпатии:
    6
    Как я понял, такой вариант сделает столько-же проходов по данным, как отдельные запросы, указанные в первом посте.
     
  9. dronvnao

    dronvnao Писатель

    Регистр.:
    14 авг 2014
    Сообщения:
    4
    Симпатии:
    0
    Нет, это уже хорошо. На пустой таблице нужно IFNULL везде будет постаивть типа

    SELECT
    IFNULL(SUM(1),0) AS `n1`,
    SUM(IF(a=0,1,0)) AS `n2`,
    SUM(IF(a=1,1,0)) AS `n3`,
    SUM(IF(a>1,1,0)) AS `n4`,
    SUM(IF(b=0,1,0)) AS `n5`,
    SUM(IF(b=1,1,0)) AS `n6`,
    SUM(IF(b>1,1,0)) AS `n7`
    FROM `z` WHERE x=1
     
  10. pastuhoff

    pastuhoff Создатель

    Регистр.:
    11 июл 2012
    Сообщения:
    49
    Симпатии:
    6
    Не совсем понял, зачем "IFNULL", если все поля "NOT NULL". Вот IF`ы как-то на CASE заменить не нужно? Не получится сделать быстрее?