Я все еще новичок в написании SQL-запросов. Интересно, есть ли лучший способ написать предложение where в следующем запросе для повышения производительности при фильтрации результатов?

Запрос:

SELECT    
    B.col1, A.col1, A.col2   
FROM 
    tblB B  
INNER JOIN 
    tblA A ON B.ID = A.ID   
WHERE   
    ((B.T_No NOT LIKE '123%' AND b.StartDate < '2001-01-01') 
     OR
     (B.T_No NOT LIKE '234%' AND b.StartDate < '2005-01-01')
    )
    AND B.BName = 'sth'
    AND B.c_Val = 33

Примечание: мне не следует использовать первичные ключи для фильтрации этих результатов.

Может кто-нибудь мне помочь?

0
user9166017 3 Янв 2018 в 03:59

2 ответа

Лучший ответ

Это ваш запрос:

SELECT B.col1, A.col1, A.col2   
FROM tblB B INNER JOIN
     tblA A
     ON B.ID = A.ID   
WHERE ((B.T_No NOT LIKE '123%' AND b.StartDate < '2001-01-01') OR
       (B.T_No NOT LIKE '234%' AND b.StartDate < '2005-01-01')
      ) AND
      B.BName = 'sth' AND
      B.c_Val = 33;

Предложение where не будет иметь большого значения для производительности. Что действительно имеет значение, так это индексы. Для этого я бы предложил tblB(BName, c_Val, StartDate, t_no, id, col). Вам также нужен индекс для tblA(id) (если он еще не объявлен уникальным или первичным ключом).

Это покрывающий индекс для запроса, означающий, что все столбцы, используемые в tblB, находятся в индексе. Это означает, что индекс может удовлетворить запрос, не обращаясь к страницам данных.

1
Gordon Linoff 3 Янв 2018 в 11:29

Я бы пошел на эти два изменения, чтобы оптимизировать этот запрос:

  1. Во-первых, я бы разделил запрос на две части в сочетании с UNION (желательно UNION ALL, если вы не заботитесь об удалении дубликатов), но также возможно с UNION DISTINCT. Это разделение позволит MySQL лучше индексировать фильтры WHERE, поскольку он не может правильно выполнять поиск в индексах при использовании условия ИЛИ.
  2. Добавьте правильные индексы.

Итак, давайте посмотрим на оптимизированный запрос:

(SELECT 
    B.col1, A.col1, A.col2
FROM
    tblB B
        INNER JOIN
    tblA A ON B.ID = A.ID
WHERE
    ((B.T_No NOT LIKE '123%'
        AND B.StartDate < '2001-01-01'))
        AND B.BName = 'sth'
        AND B.c_Val = 33) UNION DISTINCT (SELECT 
    B.col1, A.col1, A.col2
FROM
    tblB B
        INNER JOIN
    tblA A ON B.ID = A.ID
WHERE
    ((B.T_No NOT LIKE '234%'
        AND B.StartDate < '2005-01-01'))
        AND B.BName = 'sth'
        AND B.c_Val = 33)

Что касается индексов: MySQL имеет множество факторов, чтобы определить, начинать ли соединение с tblA или tblA. Поэтому с помощью предоставленной вами информации (без схемы и плана объяснения) трудно сказать, какая таблица будет первой. Таким образом, вы также можете попробовать добавить эти два варианта по одному и посмотреть, какой из них работает лучше: Вариант A:

ALTER TABLE `tblA` ADD INDEX `tblA_index_1` (`col1`, `col2`);
ALTER TABLE `tblB` ADD INDEX `tblB_index_1` (`BName`, `c_Val`, `ID`, `StartDate`, `col1`);

Вариант Б:

ALTER TABLE `tblA` ADD INDEX `tblA_index_1` (`ID`, `col1`, `col2`);
ALTER TABLE `tblB` ADD INDEX `tblB_index_1` (`BName`, `c_Val`, `StartDate`, `col1`);
1
Tomer Shay 4 Янв 2018 в 21:12