Мне паведамілі, што пры гартанні спіса адна і тая ж картка паказалася двойчы. У логах нічога, запыт звычайны, таму я патраціў паўдня на пошук памылкі ў праграме. Памылка ў самім спосабе гартаць, і ніякай драмы з канкурэнтнасцю для яе не трэба: хапае адной устаўкі.
Стэнд гэта табліца на мільён радкоў з індэксам па ключы сартавання, старонкі па 20. Першая старонка вяртае ідэнтыфікатары з 1 па 20. Далей прыходзіць 1 радок, які па парадку становіцца раней за ўсіх, а гэта звычайны выпадак, калі нехта заднім чыслом дадае запіс. І далей запытваецца другая старонка звычайным спосабам.
Старонка праз OFFSET пачынаецца з 20, то бок з радка, які чытач ужо бачыў. Радок 40 не з’яўляецца ўвогуле. Старонка па ключы вяртае з 21 па 40. Вінаватага няма: запыт з OFFSET сумленна аддае радкі з 21 па 40 бягучага парадку, а бягучы парадак на 1 радок даўжэйшы ў пачатку, чым быў, калі малявалася першая старонка.
Менавіта гэта і з’ела мае паўдня. Я шукаў гонку, слой кэшавання, няслушнае сартаванне. Шукаць няма чаго. У самой схемы ёсць уласцівасць: усё, што ўставілі або выдалілі наперадзе тваёй пазіцыі, зрушвае ўсё, што ззаду. Чытач, які гартае павольна, бачыць паўторы пасля ўставак і моўчкі прапускае радкі пасля выдаленняў.
Хуткасць, пра якую звычайна і кажуць замест гэтага
У пачатку спіса запыт з OFFSET аказваецца хутчэйшым: 1.483 мілісекунды супраць 1.774. Гэта варта сказаць уголас, бо менавіта таму ніхто нічога не мяняе: на тых старонках, якія людзі рэальна адкрываюць, просты варыянт выйграе.
На глыбіні 100000 ён каштуе ўжо 10.8 мілісекунды, а на 900000 каштуе 69.5, пры тым што запыт па ключы так і не зрушыўся з 1.5. План тлумачыць гэта адным радком: каб вярнуць 20 радкоў, база чытае 900020 і выкідвае ўсё, што ідзе да зрушэння. Запыт па ключы чытае роўна 20.
Абыход усёй табліцы робіць форму відавочнай. Старонкамі па 20 іх выходзіць 50000, і версія з OFFSET на кожнай наступнай чытае на 20 радкоў больш, чым на папярэдняй. У суме гэта каля 25 мільярдаў прачытаных радкоў на табліцы ў мільён. Версія па ключы чытае па 20 радкоў на старонку і заканчвае на мільёне. Гэта арыфметыка, а не замер, і гэта роўна тая ж арыфметыка, якую план паказаў на адной старонцы: цана старонкі роўная яе пазіцыі.
Выгрузка даных зробленая менавіта так. Яна праходзіць усе старонкі па разе, ветліва, цыклам, які нехта напісаў за паўдня. І ператварае абыход табліцы ў квадратычны, прычым ніводны радок таго кода не выглядае няслушным.
Чаго я не правяраў
Гартанню па ключы патрэбны ўнікальны давершнік. У мяне гэта першасны ключ побач з адзнакай часу. Без яго радкі з аднолькавым значэннем сартавання лягуць па абодва бакі мяжы старонкі. Гэтага я не мераў, хоць чакаю, што паўтор адтворыцца іншым спосабам.
Люстэрка гэтай памылкі, то бок выдаленне наперадзе пазіцыі, з-за якога радок моўчкі знікне, я не праганяў, а разважыў. І ў гартання па ключы ёсць сапраўдная цана: перайсці адразу на 57 старонку нельга, толькі наперад і назад. Значыць любы інтэрфейс з нумараванымі старонкамі сам просіць тую схему, якая памыляецца ў ліку.
Вузкае сцвярджэнне пра тое, што чыніць першым. Аргумент пра хуткасць тычыцца глыбіняў, да якіх большасць праграм не даходзіць. Аргумент пра карэктнасць працуе на другой старонцы.