2017-01-17 11 views
1

Глядя на various answers for ORDER BY with CASE like this one, я вижу, что то, что я вынужден делать в этом устаревшем приложении, вероятно, является экспертным методом; однако он слишком медленный, когда строки меньше тривиальных (строки из 100 000 или более загрузок страниц составляют 10 секунд).mysql ORDER BY with CASE - слишком медленно, быстрее?

Обратите внимание, что исходный запрос предназначен для решения, по-видимому, распространенной проблемы, когда аналитику запроса нужны даты, которые отсортированы в пустом порядке, как они обычно сортируются. В этом случае datefirstprinted должен опускаться, но все записи, которые не печатаются, должны быть заполнены в верхней части списка.

Оригинал Запрос решает эту проблему, но суть вопроса в том, чтобы избежать попадания filesort производительности, который поставляется с производный столбец notprintedyet.

Оригинал Запрос

SELECT SQL_NO_CACHE 
    id, daterun, datefirstprinted, 
    case datefirstprinted when "0000-00-00 00:00:00" then 1 else 0 end as notprintedyet 
FROM 
    patientrecords 
WHERE 
    dateuploaded <> '0000-00-00 00:00:00' 
ORDER BY 
    notprintedyet desc,         /* ordered via alias */ 
    datefirstprinted desc 
LIMIT 10; 

время 1.52s


я обнаружил, что не сортировать по псевдониму notprintedyet экономит немного:

немного быстрее Запрос

SELECT SQL_NO_CACHE 
    id, daterun, datefirstprinted, 
    case datefirstprinted when "0000-00-00 00:00:00" then 1 else 0 end as notprintedyet 
FROM 
    patientrecords 
WHERE 
    dateuploaded <> '0000-00-00 00:00:00' 
ORDER BY 
    datefirstprinted = "0000-00-00 00:00:00" desc,  /* directly ordered */ 
    datefirstprinted 
LIMIT 10; 

время 1.37s


Оптимальная скорость, но отсутствует необходимый сортировкой пустой даты S первый

SELECT SQL_NO_CACHE 
    id, daterun, datefirstprinted, 
    case datefirstprinted when "0000-00-00 00:00:00" then 1 else 0 end as notprintedyet 
FROM 
    patientrecords 
WHERE 
    dateuploaded <> '0000-00-00 00:00:00' 
ORDER BY       
    datefirstprinted          /* not ordered properly */ 
LIMIT 10; 

время 0.48s


Я попытался с помощью view

create view notprinted_patientrecords as (
    SELECT id, daterun, datefirstprinted, case datefirstprinted when "0000-00-00 00:00:00" then 1 else 0 end notprintedyet 
    FROM patientrecords 
    WHERE dateuploaded <> '0000-00-00 00:00:00' 
); 

, к сожалению, когда я бегу explain

explain select * from notprinted_patientrecords order by notprintedyet desc limit 10; 

это показывает, что я все еще использую filesort и принимает1.51sака не экономии на всех


Будет ли он быстрее, если datefirstprinted по умолчанию NULL?

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


Что еще мы могли бы попробовать? Хранимые процедуры? Функции?


ОБНОВЛЕНИЕ

Как предложил @strawberry - ORDER BY ДЕЛУ

... 
ORDER BY       
    case datefirstprinted when "0000-00-00 00:00:00" then 1 else 0 end, datefirstprinted 
LIMIT 10; 

время 1.52s


по просьбе @ e4c5, то explain выход:

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: patientrecords 
     type: range 
possible_keys: dateuploaded,uploads_report 
      key: dateuploaded 
     key_len: 5 
      ref: NULL 
     rows: 299095 
     Extra: Using index condition; Using filesort 

за исключением не упорядочено должным образом, который имеет следующую дисперсию

 rows: 10 
     Extra: Using where 

создать таблицу заявление

*************************** 1. row *************************** 
Table: patientrecords 
Create Table: CREATE TABLE `patientrecords` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `datecreated` datetime NOT NULL, 
    `dateuploaded` datetime NOT NULL, 
    `daterun` datetime NOT NULL, 
    `datebilled` datetime NOT NULL, 
    `datefirstprinted` datetime NOT NULL, 
    `datelastprinted` datetime NOT NULL, 
    `client` varchar(5) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `dateuploaded` (`dateuploaded`), 
    KEY `daterun` (`daterun`), 
    KEY `uploads_report` (`dateuploaded`,`client`), 
    KEY `datefirstprinted` (`datefirstprinted`), 
    KEY `datelastprinted` (`datelastprinted`) 
) 
+1

Вы пытаетесь ускорить запрос, который занимает одну или две миллисекунды? Просто не имеет смысла. –

+0

@gordonlinoff - не знаю, почему я поставил «мс» во времена ... это в секундах. thx - обновлено. – WEBjuju

+0

Вы попробовали заказать по 'case ...' – Strawberry

ответ

1

Глядя на вашем столе, то первое, что нужно отметить, что следующий индекс является излишним

KEY `dateuploaded` (`dateuploaded`), 

его роль может быть fullfilled этим одним

KEY `uploads_report` (`dateuploaded`,`client`), 

Так давайте уронить ключ dateuploaded. Неясно, используете ли вы столбец клиента в любых запросах. Если вы этого не сделаете, я считаю изменение индекса следующим образом даст вам большую скорость до

KEY `uploads_report` (`dateuploaded`,`datefirstprinted`,`client`), 

Это потому, что MySQL может использовать только один индекс для каждой таблицы. Поскольку индекс в столбце dateuploaded используется в предложении where, индекс для datefirstprinted не может быть использован. Но если вы объедините два столбца в один и тот же индекс, его можно использовать как в сортировке, так и в том, где.

После того, как вы сделали выше индекс, это один, вероятно, может быть отброшен:

KEY `datefirstprinted` (`datefirstprinted`), 

Имея меньше индексов сделают ваши вставки и обновление быстрее.

+0

Учитывая, что [«Конкатенированный индекс - это один индекс для нескольких столбцов ... (и) индекс с двумя столбцами не поддерживает поиск на вторая колонка одна »] (http://use-the-index-luke.com/sql/where-clause/the-equals-operator/concatenated-keys#sb-full-table-scan), это разбивает десятки других устаревших запросов в приложении и, похоже, ничего не делает для этого вопроса. – WEBjuju

+0

Обратите внимание на это предостережение: «Не ясно, используете ли вы столбец клиента в любых запросах. Если вы этого не сделаете, я верю, что ваш индекс изменится следующим образом: « – e4c5

+0

Хмм ... посмотрев дальше, я думаю, вы привели меня к решению. Как мне представить, что сработало, потому что на самом деле это сообщение, которое привело меня к этому? Должен ли я редактировать ваш пост, указывая, что сработало для меня в обновлении? – WEBjuju

1

Эти идеи узнали о сцепленных индексов благодаря @ e4c5, я попытался добавить ключ на две колонки (колонки, используемые в where и колонки, используемой в case на основе order пункт):

alter table 
    patientrecords 
add index 
    printedvsuploaded (datefirstprinted, dateuploaded); 

Это изначально было не эффект, так как mysql продолжал использовать индекс dateuploaded.

Однако добавление force index сокращает время запроса:

SELECT SQL_NO_CACHE 
    id, daterun, datefirstprinted 
FROM 
    patientrecords 
FORCE INDEX (printedvsuploaded) 
WHERE 
    dateuploaded <> '0000-00-00 00:00:00' 
ORDER BY 
    case when datefirstprinted = "0000-00-00 00:00:00" then 1 else 0 end desc, 
    datefirstprinted 
LIMIT 10; 

время 0,64 секунды

стоит отметить, что я согласен с @ e4c5, что дополнительный индекс в конечном итоге привести пишет иметь производительность; Я рассчитываю на разработку другой дорожной карты, чтобы помочь уменьшить количество индексов. на данный момент реализация этого приведет к уменьшению загрузки 10-секундной страницы больших наборов результатов в управляемый 3-секундный диапазон и затем будет решением, которое будет реализовано.

+0

Вы пробовали использовать индекс вообще (например, с 'ignoreindex' или принудительным первичным ключом)? Текущий индекс не должен улучшать ваш запрос, по сравнению с первичным ключом. – Solarflare

 Смежные вопросы

  • Нет связанных вопросов^_^