更快的查询计划?

时间:2019-03-06 15:23:16

标签: sql sql-server

一个简单的问题。我有一个数据库,我试图从3行的表中获取所有匹配项。

RECEIPT | ORIGINAL_RECEIPT | EXCHANGED_RECEIPT

51651651 |     1245678      |   58453874

我正在使用的查询现在可以完美且快速地运行

select distinct RECEIPT from RECEIPT_DATA WHERE ORIGINAL_RECEIPT = '1245678'
UNION
select distinct ORIGINAL_RECEIPT from RECEIPT_DATA WHERE ORIGINAL_RECEIPT = '1245678'
UNION
select distinct EXCHANGED_RECEIPT from RECEIPT_DATA WHERE ORIGINAL_RECEIPT = '1245678'
order by RECEIPT asc

然后应返回

51651651
1245678 
58453874     

很明显,我的行有很多,并且ORIGINAL_RECEIPT可能有很多交换,而且全部。

就像我说的那样,这很完美,但是我很好奇还有什么其他方法可以解决?有没有不搜索数据库3次? 我听说案例可以解决这个问题吗?也许还有交叉申请?

2 个答案:

答案 0 :(得分:1)

您标记了SSMS,因此,我将使用APPLY代替UNION

SELECT DISTINCT RDD.RECEIPTS
FROM RECEIPT_DATA RD CROSS APPLY 
     ( VALUES (RECEIPT), (ORIGINAL_RECEIPT), (EXCHANGED_RECEIPT) 
     ) RDD(RECEIPTS)
WHERE RD.ORIGINAL_RECEIPT = 1245678;

DISTINCT实际上是不必要的,因为您使用了UNION,因此它将为您删除重复项。

但是,为了获得更好的性能,您将需要在RECEIPT_DATA(ORIGINAL_RECEIPT)上建立索引。

答案 1 :(得分:1)

我建议:

CREATE DEFINER=`root`@`localhost` PROCEDURE `select_medicoes`(
    whereCondicao varchar(200))

BEGIN
DECLARE ID_novo int;
DECLARE ID_Variavel int;
DECLARE ID_Cultura int;
DECLARE NumMed int;
DECLARE DataHoraMed date;
DECLARE ValorMed int;
DECLARE done INT DEFAULT FALSE;

DECLARE curs_medicoeslog cursor for 
    (SELECT *
    FROM `dba`.medicoes
    WHERE `whereCondicao`);

DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
SELECT `whereCondicao`;

OPEN curs_medicoeslog;
    read_loop: LOOP
        FETCH curs_medicoeslog INTO ID_Variavel, ID_Cultura, NumMed, DataHoraMed, ValorMed;
            INSERT INTO log_medicoes (IDVariavel, IDCultura, NumMedicao, DataHoraMedicao, ValorMedicao, Utilizador, `Data`, Operacao) 
            VALUES (ID_Variavel, ID_Cultura, NumMed, DataHoraMed, ValorMed, current_user(), now(), 'S');
        IF done THEN
            LEAVE read_loop;
        END IF;
    END LOOP;
CLOSE curs_medicoeslog;
END

而且,您希望在select DISTINCT (CASE WHEN n.n = 1 THEN RECEIPT WHEN n.n = 2 THEN ORIGINAL_RECEIPT WHEN n.n = 3 THEN EXCHANGED_RECEIPT END ) from RECEIPT_DATA CROSS JOIN (SELECT 1 as n UNION ALL SELECT 2 UNION ALL SELECT 3) n WHERE ORIGINAL_RECEIPT = '1245678'; 上建立索引。

您的查询版本正在执行大量重复消除操作-既在每个子查询中,也使用RECEIPT_DATA(ORIGINAL_RECEIPT)。这简化了重复消除。

但是,最大的问题可能是UNION上缺少索引。

此版本可在MySQL和SQL Server中使用。但是,在SQL Server中,我将使用ORIGINAL_RECEIPT来表达它。