2014-10-27 2 views
2

У меня есть две таблицы:Выравнивание по левому краю, кажется, препятствует производительности SQL-запрос чрезвычайно

Таблица A:

Name, isPair 

Таблица B:

Name1, Name2, Status 

Это мой запрос:

SELECT Name 
FROM A 
LEFT JOIN B ON (A.Name = B.Name2) 
WHERE A.isPair = 'T' AND (B.status <> 'valid' OR B.status IS NULL) 

У меня есть миллионы строк в обе таблицы. По текущим запросам скорость займет более 3 месяцев. Я проиндексировал обе таблицы соответственно. Когда я изначально выполнял INNER JOIN, осталось всего 10 минут, но я обнаружил, что запрос не возвращал строки, которые не были в столбце Name2 в таблице B, что было проблемой, поскольку они мне нужны.

+1

Вы присоединяетесь к имени, которое, я думаю, будет либо в столбце VARCHAR, либо в столбце CHAR. См. Http://stackoverflow.com/questions/332300/is-there-a-real-performance-difference-between-int-and-varchar-primary-keys – rurouni88

+0

В дополнение к @ rurouni88 ... что вы подразумеваете под «соответствующим образом индексировали обе таблицы»? – TeamTam

+0

@ rurouni88 спасибо, но это не главная причина медленности.Я несколько раз присоединил обе таблицы к другим таблицам, и запросы заняли менее 10 минут. – Mitchell

ответ

3

Этот запрос может возвращать правильные результаты быстрее, или он может возвращать неверные результаты без улучшения скорости

Это все на основе знаний SQL Server, но я предполагаю, что InnoDB имеет те же характеристики.

SELECT Name 
FROM A 
WHERE A.isPair = 'T' 
AND NOT EXISTS (
    SELECT 1 FROM B 
    WHERE A.Name = B.Name2 
    AND B.status = 'valid' 
    ) 

Надеюсь, я правильно переработал логическую логику.

Перед тем, как искали записи в том, что не было ни одного совпадения в B или матч со статусом <> действительным

Новый запрос возвращает записи из A, где он не может найти совпадения в B со статусом = действительный. Надеюсь, это одно и то же.

Есть два понятия базы данных, которые я использую здесь:

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

  2. оператор <> не является sargable, который означает, что он не может использовать любой индекс, который содержит столбец status ... то есть он не может явно искать индекс для отсутствия значения, он может искать только индекс для определенного значения (с). Таким образом, я изменил его = по этой причине, а также потому, что он поддерживает NOT EXISTS логику

Опять же, я не знаю много о InnoDB, но я уверен, что, если он не имеет этих ограничений уловок были бы скопированы Oracle и Microsoft уже.

Сравнивая планы запросов, вы получите некоторое представление о том, имеет ли этот переписчик какую-либо разницу. Кроме того, сравнение планов запросов между существующими версиями INNER и OUTER вашего запроса может проливать свет на вещи.

+0

Я слышал это несколько раз, что по некоторым причинам анти-объединения в MySQL работают более эффективно при реализации с использованием 'LEFT JOIN ... WHERE ... IS NULL' вместо использования' NOT EXISTS'. Следовательно, имеет смысл попробовать другую альтернативу: '... LEFT JOIN B ON' A.Name = B.Name2 AND B.status = 'valid' WHERE B.Name2 IS NULL'. Я не эксперт по MySQL, поэтому просто комментирую (но не стесняйтесь добавлять эту версию к своему ответу, если считаете это целесообразным). –

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