Оптимизация SQL-запросов - проблемы производительности - PullRequest
0 голосов
/ 22 января 2019

У меня есть следующий запрос SQL, который я хочу оптимизировать:

select table1.tiers as col1, table1.id_item as col2 
from items table1 
where (table1.tiers is not null) 
  and table1.tiers<>''
  and table1.id_item = (select max(table2.id_item)
                        from items table2
                        where table1.tiers=table2.tiers) 
  and table1.n_version_item=(select max(table2.n_version_item) 
                             from items table2 
                             where table2.id_item=table1.id_item)

Я пробовал это:

select table1.tiers as col1, table1.id_item as col2 
from items table1 
where (table1.tiers is not null) 
  and table1.tiers<> '' 
  and CONCAT(table1.id_item,table1.n_version_item) =  (select CONCAT(max(table2.id_item),max(table2.n_version_item)) 
                                                       from items table2
                                                       where table2.id_item=table1.id_item 
                                                         and table1.tiers=table2.tiers)

Но я не получу тот же результат. Исходный первый запрос возвращает меньше строк, чем измененный. Обратите внимание, что у элементов таблицы есть первичный ключ (id, версия), и для каждой пары может быть затронут уровень.

Ответы [ 3 ]

0 голосов
/ 22 января 2019

Я думаю, что вы хотите:

select i.tiers as col1, i.id_item as col2 
from items i 
where i.tiers is not null and  -- redundant, but I'm leaving it in
      i.tiers <> '' 
      (id_item, n_version_item) = (select i2.id_item, max(i2.n_version_item)
                                   from items i2
                                   where i2.tiers = i.tiers
                                   order by i2.id_item desc, i2.n_version_item desc
                                   limit 1
                                  );

Для этой версии вам нужен индекс на items(tiers, id_item, n_version_item).

0 голосов
/ 25 января 2019

Если вы скрываете столбец внутри «функции» (CONCAT, DATE и т. Д.), Никакой индекс не может быть использован для повышения производительности.Это исключает вашу вторую версию из рассмотрения.

С этим связано использование «конструкторов строк» ​​(см. Комментарий a_horse_with_no_name).Исторически они были плохо оптимизированы;избежать их.Я имею в виду WHERE (a,b) IN ( (1,2), ...) или другие варианты.

Теперь давайте рассмотрим

  and table1.id_item = (select max(table2.id_item)
                    from items table2
                    where table1.tiers=table2.tiers) 

table2, которым нужно INDEX(tiers, id_item) в этом порядке.С таким подзапросом очень быстро.Другие подзапросы нуждаются в INDEX(id_item, n_version_item) Те, что входят в остальное:

  and table1.id_item = <<value>>

Теперь давайте посмотрим на все

where (table1.tiers is not null) 
  and  table1.tiers<>''
  and  table1.id_item = <<value>>
  and  table1.n_version_item = <<value>>

= легко оптимизировать;другие нет.Итак, давайте создадим

INDEX(id_item, n_version_item,  -- in either order
      tiers)    -- last

Используя указанный мной порядок, вы также можете избежать необходимости INDEX(id_item, n_version_item), который был упомянут выше.

(Это поможет, если вы предоставите SHOW CREATE TABLE; Iнужно знать, что такое PK, и некоторые другие вещи.)

В качестве бонуса эти индексы будут "покрывающими индексами".

В качестве заключительного примечания (второстепенного):

where (table1.tiers is not null) 
  and  table1.tiers<>''

Было бы лучше выбрать только одну кодировку (NULL против пустой строки) для того, что вы указываете таким образом.

0 голосов
/ 22 января 2019

При использовании функции она запрещает использование индекса, поэтому CONCAT(table1.id_item,table1.n_version_item) не будет читать индекс, если только его индекс основан на функции. однако в качестве a_horse_with_no_name, упомянутого в комментариях, вы можете использовать ниже:

select itm.tiers as col1, itm.id_item as col2 
from items itm
where itm.tiers is not null 
  and itm.tiers<>''
  and (itm.id_item , itm.n_version_item)= (select 
 max(item_sub.id_item),max(item_sub.n_version_item)
                        from items item_sub
                        where itm.tiers=item_sub.tiers) 

Затем вам нужно проверить план запроса, какой индекс использует (вы можете запустить индекс со столбцом tiers и другим индексом для id_item и n_version_item)

...