2015-06-04 3 views
3

Я уже возился с производительностью запросов для системы с разбивкой по страницам, чтобы сделать выбор данных как можно быстрее, но я столкнулся с чем-то, что я не совсем понимаю. Насколько мне известно, когда используется предел со смещением, MySQL должен перебирать каждую строку перед смещением и затем отбрасывать их, поэтому теоретически запрос со смещением в 10 000 будет намного медленнее, чем один без, что обычно верно так как в этом случаеВыбор MySQL с помощью смещения быстрее, чем без смещения

select SQL_NO_CACHE * from `customers` where `NetworkID`='\func uuid()' 
    order by `DateTimeAdded` desc limit 0, 100; 
/* finishes in 2.497 seconds */ 

select SQL_NO_CACHE * from `customers` where `NetworkID`='\func uuid()' 
    order by `DateTimeAdded` desc limit 10000, 100; 
/* finishes in 2.702 seconds */ 

Но, если я использую внутреннее соединение, чтобы соединить таблицу к себе только UserID колонке для выполнения сортировки и ограничения, это последовательно быстрее с смещением 10000, чем без него, который полностью пьет меня. Например, здесь будет

select SQL_NO_CACHE * from `customers` 
    inner join (select `UserID` from `customers` where `NetworkID`='\func uuid()' 
     order by `DateTimeAdded` desc limit 100) 
    as `Results` using(`UserID`) 
/* finishes in 1.133 seconds */ 

select SQL_NO_CACHE * from `customers` 
    inner join (select `UserID` from `customers` where `NetworkID`='\func uuid()' 
     order by `DateTimeAdded` desc limit 10000, 100) 
    as `Results` using(`UserID`) 
/* finishes in 1.120 seconds */ 

Почему запрос с использованием смещения всегда выполняется быстрее, чем запрос без смещения?


Объясняет:

Я разместил Google Docs таблицы здесь с explains содержанием here

Примечание: Тесты выше были сделаны в PHP цикл 20 раз каждый

Примечание : customers - вид, а не базовый стол

+0

попробуйте различные смещения, посмотрите, получится ли у вас одинаковое направление. может быть, это конкретное смещение имеет очень простое соединение. –

+0

У меня есть, если я делаю это с 30 000 даже, он по-прежнему будет последовательно быстрее, чем запрос без смещения. –

+0

'оптимизируйте 'таблицу и посмотрите, одинаково ли это (нейтрализуйте все неизвестные факторы сначала) –

ответ

1

Дело 1: Оптимизатор может использовать индекс на ORDER BY. LIMIT 10 будет быстрее, чем LIMIT 10000,10, потому что он может прекратить чтение строк раньше.

Дело 2: Оптимизатор не может (или не хочет) использовать индекс для ORDER BY. В этом случае собирается весь набор строк (после WHERE), этот набор сортируется, и только тогда применяются OFFSET и LIMIT. В этом случае значение OFFSET не имеет большого значения; большую часть времени потребляли выборки строк, их фильтрацию и сортировку.

INDEX(x,y) 
SELECT ... WHERE x=2    ORDER BY y LIMIT ... -- case 1 
SELECT ... WHERE x=2 AND deleted=0 ORDER BY y LIMIT ... -- case 2 

INDEX(NetworkID, DateTimeAdded)   -- composite 
SELECT ... WHERE NetworkID='...' ORDER BY DateTimeAdded DESC ... -- Case 1 

INDEX(NetworkID), INDEX(DateTimeAdded) -- separate 
SELECT ... WHERE NetworkID='...' ORDER BY DateTimeAdded DESC ... -- Case 3 

Случай 3 может быть как случай 1, потому что мощь использование INDEX(DateTimeAdded). Или оптимизатор выбирает использовать другой индекс, то это медленный случай 2. В любом случае, это не так хорошо, как использование составного индекса, который может обрабатывать как WHERE, так и ORDER BY.

Если вам удастся добраться до Case 1, я рекомендую вам также «запомнить, где вы остановились», чтобы сделать Pagination еще более эффективным. См. my Pagination blog.

More on creating INDEXes.

+0

Да, я читал тонну о разбиении на страницы, и я столкнулся с стратегиями «запоминания того, где я остановился», но ни один из них действительно не помог бы мне в моей ситуации. Причина 1 заключается в том, что это всегда требует наличия у меня числовых данных, которые я просто не могу использовать, потому что у меня несколько серверов, которые сливаются. Причина 2 заключается в том, что я показываю отфильтрованное подмножество данных, которое может быть упорядочено пользователем каким-либо образом, что означает, что данные * никогда * в численном порядке. –

+0

Я хотя бы объяснил, почему 'OFFSET' не влияет на скорость? (А именно, что большую часть времени произошло раньше, чем применение «OFFSET».) –

+0

Да, я верю, что вы хотя и объяснили, почему мои запросы кажутся странными, и спасибо за это! –

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