Проблема производительности операторов SQL в Informix - PullRequest
1 голос
/ 22 февраля 2011

У меня есть SQL-оператор Informix, который запускается годами.Кто-нибудь видит какой-либо способ его оптимизации, чтобы это не заняло так много времени?

SELECT * FROM OriginalTable WHERE type = 'S' AND flag <> 'S' INTO TEMP TempTableA;

SELECT * FROM OriginalTable WHERE type = 'Z' AND flag <> 'S' INTO TEMP TempTableB;

UPDATE OriginalTable SET flag = 'D' WHERE Serialnumber in
(
select Serialnumber from TempTableA
WHERE NOT EXISTS(SELECT * FROM TempTableB
               WHERE TempTableB.Col1 = TempTableA.Col1
                 AND TempTableB.Col2 = TempTableA.Col2)
) 

У меня в OriginalTable около 300 миллионов строк, TempTableA 93K строк и TempTableB 58K строк.

Ответы [ 3 ]

2 голосов
/ 23 февраля 2011
Update OriginalTable 
Set flag = 'D' 
Where Type = 'S'
    And Flag <> 'S'
    And Not Exists  (
                    Select 1
                    From OriginalTable As T1
                    Where T1.Type = 'Z'
                        And T1.flag <> 'S'
                        And T1.Col1 = OriginalTable.Col1
                        And T1.Col2 = OriginalTable.Col2
                    )
0 голосов
/ 22 февраля 2011

По аналогии с @tombom.Предварительно запрашивайте только те столбцы, которые вам нужны, чтобы временная таблица была меньше.Если вы имеете дело с таблицей из 60 столбцов, вы заполняете намного больше, чем просто 3-4 столбца, в которых основное внимание уделяется действительным серийным номерам.Предварительно протестируйте запрос, чтобы убедиться, что он дает правильный набор, который вы ожидаете, а затем примените его к своему обновлению SQL.

Итак, внутренний запрос - это те, которые НЕ ХОТИТЕ ...вы сравниваете только столбец 1 и столбец 2 из этой таблицы, это все, что я предварительно запрашиваю.Затем я делаю левое соединение с этим внутренним набором результатов на COL1 и COL2.Я знаю, что вы хотите ИСКЛЮЧИТЬ ЭТУ НАЙДЕННУЮ В ЭТОМ наборе результатов ... Вот почему в предложении OUTER WHERE я добавил "AND ExcludeThese.Col1 IS NULL".Таким образом, любые экземпляры из OT1, которые никогда не существовали в подзапросе, хороши для выполнения (через левое соединение), и те, которые БЫЛИ НАЙДЕНЫ, будут иметь совпадение на col1 и col2, но ЭТО будет исключено через "и" предложение I 've описал.

SELECT OT1.SerialNumber
    FROM OriginalTable OT1
        LEFT JOIN ( select OT2.Col1,
                           OT2.Col2
                       FROM OriginalTable OT2
                       where OT2.type = 'Z' 
                         AND OT2.flag <> 'S' ) ExcludeThese
           ON OT1.Col1 = ExcludeThese.Col1
          AND OT1.Col2 = ExcludeThese.Col2
    WHERE  OT1.type = 'S' 
       AND OT1.flag <> 'S'
       AND ExcludeThese.Col1 IS NULL
    ORDER BY
       OT1.SerialNumber
    INTO 
       TEMP TempTableA;  

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

SELECT OT1.SerialNumber,
       OT1.Col1,
       OT1.Col2,
       ExcludeThese.Col1 JoinedCol1,
       ExcludeThese.Col2 JoinedCol2
  from  <keep rest of query intact>

. Теперь вы сможете увидеть серийный номер и экземпляры этих столбцов.которые будут или не будут присоединены к результирующему набору «excludeThese» ... Попробуйте еще раз, но удалите только предложение «AND ExcludeThese.Col1 IS NULL», и вы увидите другие строки и ПОЧЕМУ они исключаются - то естьесли у вас есть какие-либо вопросы к содержанию.

Как только вы будете удовлетворены предварительным запросом ... который будет возвращать только один столбец SerialNumber, который можно индексировать / оптимизировать, так как вы тянете ввременная таблица, создайте индекс, затем примените свое обновление.

UPDATE OriginalTable 
   SET flag = 'D' 
   WHERE Serialnumber in ( select Serialnumber from TempTableA  );
0 голосов
/ 22 февраля 2011

Мне было лень тестировать тестовые данные, но, может быть, это подойдет?

SELECT col1, col2, 
CASE WHEN type = 'S' THEN 1 
ELSE WHEN type = 'Z' THEN 2 END AS filteredType 
FROM OriginalTable WHERE (type = 'S' OR type = 'Z') AND flag <> 'S' INTO TempTable;

UPDATE OriginalTable SET flag = 'D' WHERE Serialnumber IN
(
SELECT t1.Serialnumber FROM TempTable t1
LEFT JOIN TempTable t2 ON (t1.col1 = t2.col2 AND t1.col2 = t2.col2)
WHERE t1.filteredType = 1
AND t2.filteredType = 2 
AND t2.Serialnumber IS NULL
)

Таким образом, вы можете пропустить одну загрузку во временную таблицу.С другой стороны, не будет никакого индекса для нового столбца FilterType.

Кроме того, я не имею представления о informix.Надеюсь, это поможет в любом случае.

...