
Новые сообщения [новые:0]
Дайджест
Горячие темы
Избранное [новые:0]
Форумы
Пользователи
Статистика
Статистика нагрузки
Мод. лог
Поиск
|
|
02.09.2002, 19:06:24
|
|||
|---|---|---|---|
|
|||
Возвращение рухнувшей Веры |
|||
|
#18+
На с.д. вопрос qu-qu был очень красивый. Надо было просто его более точно спозиционировать, что речь идет не о банальном ORDER BY, а о внутреннем устр-ве стр-р хр-я данных в SQL Server. Т.е. как и когда он выбирает принадлежащие объекту страницы: по 2-направленному списку, по битовой карте аллоцирования или еще как-то. Вот мои 2 цента к задаче qu-qu.\r \r 1. \r use Northwind\r \r drop table t\r create table t (id int identity, a char(8000) default replicate(\'*\', 8000))\r go\r set identity_insert t on\r declare @i int\r set @i = 10\r while @i < 20 begin\r set @i = @i + 1\r insert t (id) values (@i)\r end\r \r select * from t\r \r --Все вроде по порядку, как вставляли. Ну-ка еще немного:\r \r declare @j int\r set @j = 0\r while @j < 10 begin\r set @j = @j + 1\r insert t (id) values (@j)\r end\r \r select * from t\r \r --Пошли в конец, потому что их добавили потом. Ну что ж пока вроде все логично. Проведем еще эксперимент:\r \r 2.\r select * into Ords from Orders\r \r set identity_insert Ords on\r declare @i int\r set @i = 9000\r while @i <= 9975 begin \r insert Ords (OrderID) values (@i)\r set @i = @i + 1\r end\r \r --Смотрите-ка, а здесь новодобавленные записи почему-то выдаются сначала. Может, это таблица такая?\r \r declare @j int\r set @j = 9976\r while @j <= 10000 begin \r insert Ords (OrderID) values (@j)\r set @j = @j + 1\r end\r \r --А теперь insertы идут в конец таблицы. Фигня какая-то. М.б. кто-нибудь объяснит?\r -----------------------------------------------------------------------------------------------------\r \r declare @NorthwindID int, @OrdsID int\r select @NorthwindID = db_id(\'Northwind\'), @OrdsID = object_id(\'Ords\')\r dbcc traceon(3604)\r dbcc tab(@NorthwindID, @OrdsID) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
02.09.2002, 19:37:16
|
|||
|---|---|---|---|
Возвращение рухнувшей Веры |
|||
|
#18+
Это шутка или вопрос ? :)) В BOL честно написано, что порядок выдачи записей не предсказуем. И все, точка, уверуйте. Вообще у меня есть книга с толкованиями Святого писания :), если правда надо могу почитать на ночь ... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
02.09.2002, 19:44:20
|
|||
|---|---|---|---|
Возвращение рухнувшей Веры |
|||
|
#18+
2YellowMan А вот ето ВЫ честно зря - если кто и понимает здесь все тонкости SQL'я со всеми вытекающими так ето Дед Маздай. ЗЫ 2Дед Маздай Не подумайте что подлизываюсь ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
02.09.2002, 19:55:48
|
|||
|---|---|---|---|
Возвращение рухнувшей Веры |
|||
|
#18+
Очень рад за товарища - я вот чем дальше, тем меньше понимаю :) Данные SQL ищет либо по индексному дереву либо сканом, тут уж не поспоришь. При этом я подозреваю что сначала смотрятся не устаревшие страницы в кеше, а потом уже, если не хватает, он головкой дергает туда-сюда, причем сначала то, что поближе к текущему положению головы на диске в тайной надежде, что вдруг не придется с дорожки на дорожку скакать. А поскольку содержимое кеша и положение головы на диске есть вещь непредсказуемая - результат будет непредсказуем тоже. Напишешь ему ORDER BY - пожалуйста, сначала данные, потом сортировка, все честно. ORDER BY по кластерному индексу - отдельный случай, не так ли ? А вообще, я в литературе посмотрю... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
02.09.2002, 20:06:15
|
|||
|---|---|---|---|
Возвращение рухнувшей Веры |
|||
|
#18+
Кстати, сервер в примере 2К ? Identity меняет картину, при его наличии в 2К данные будут действительно возвращаться в том же порядке, как вставлялись ( почему-то сдается мне SQL держит ссылки на них в виде непрерывного куска или начала и длинны). Но если кто скажет, что так будет всегда, я только улыбнусь в ответ. Вот так :)) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
02.09.2002, 20:34:43
|
|||
|---|---|---|---|
|
|||
Возвращение рухнувшей Веры |
|||
|
#18+
"При этом я подозреваю что сначала смотрятся не устаревшие страницы в кеше, а потом уже, если не хватает, он головкой дергает туда-сюда" drop table Ords select * into Ords from Orders --Посмотрим ест.порядок чтения стр-ц select * from Ords --Создадим индекс, чтобы положить в кэш последнюю стр-цу данных create index ix on Ords(OrderID) --Посмотрим, какие страницы принадлежат таблице Ords declare @NorthwindID int, @OrdsID int select @NorthwindID = db_id('Northwind'), @OrdsID = object_id('Ords') dbcc traceon(3604) dbcc tab(@NorthwindID, @OrdsID) --Очистим кэш dbcc dropcleanbuffers --И положим ее туда select top 1 * from Ords order by OrderID desc --Видите: за вычетом служебных и индексных страниц сейчас в буфере сидит одна-единственная последняя страница данных dbcc buffer('Northwind', 'Ords') /* В моем случае это PAGE: (1:97427) --------------- BUFFER: ------- BUF @0x00DD6B40 --------------- bpage = 0x1D44A000 bhash = 0x00000000 bpageno = (1:97427) bdbid = 6 breferences = 0 bstat = 0x9 bspin = 0 bnext = 0x00000000 PAGE HEADER: ------------ Page @0x1D44A000 ---------------- m_pageId = (1:97427) m_headerVersion = 1 m_type = 1 m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x8020 m_objId = 1074102867 m_indexId = 0 m_prevPage = (1:97426) m_nextPage = (0:0) pminlen = 58 m_slotCnt = 37 m_freeCnt = 912 m_freeData = 7206 m_reservedCnt = 0 m_lsn = (22278:131:53) m_xactReserved = 0 m_xdesId = (0:10398703) m_ghostRecCnt = 0 m_tornBits = 1 */ --По идее данные с нее должны выдаться раньше, чем с остальных, к-е лежат на диске. Проверяем: select * from Ords --И видим, что это не так. Порядок чтения страниц не изменился. Может, он головкой как-то не так двигает? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
03.09.2002, 01:14:18
|
|||
|---|---|---|---|
Возвращение рухнувшей Веры |
|||
|
#18+
Т.е. Вы думаете, что select top 1 * from Ords order by OrderID desc прочтет только последнюю страницу с диска ? В общем логично, если только не принимать во внимание, что max(OrderID) может быть физически хрен знает где, не так ли ? А вот попробуйте create CLUSTERED index ix on Ords(OrderID desc) для гарантии и select top 1 * from Ords WITH INDEX (ix) order by OrderID desc Я почему пишу попробуйте - пару лет назад я сильно обжегся на этом. Ситуация была как у господина qu-qu, только во временной таблице было не 80 а порядка 500К записей и на тестовой базе все было тип-топ, а вот на рабочей - каждый раз новые значения. Было замечено - когда на боевом сервере отваливались все юзеры (ну или их отваливали, кто теперь разберет :)), минут через 20 он приходил в себя и выдавал стабильные значения. Изрядно задумавшись, я в неофициальной беседе спросил ребят из SQL Server Core development group и получил такой ответ - "Серега, не выеживайся, пиши ORDER BY, а то что ты получал иногда якобы правильные результаты - это всего лишь вырожденный случай". С тех пор я уверовал и не выеживаюсь, чего и всем советую. 100% если Вы и получите какие-то результаты, и сделаете на их основе какие-то выводы, без исходников это использовать бесполезно, а исходников нет ни у меня ни у Вас. А строить выводы или не дай Б-г что-то рабочее на предположениях - мои решпекты и пожелание всяческих удач. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
03.09.2002, 11:01:42
|
|||
|---|---|---|---|
Возвращение рухнувшей Веры |
|||
|
#18+
2 Дед Маздай Спасибо, дедушка, за моральную поддержку... :-)), (наверное ты не забыл еще наши "баталии" по поводу рекордсетов ADO, во время которых мы вроде как "выпили на брудершафт"). Действительно, по большей части всю эту бодягу с "Верой" ("или - Надей?") я так долго тянул только затем, чтобы народ хоть немного начал думать собственной головой, а не BOL-овской, Саукаповской, или еще чьей-то... Да мало кто - обратил на это внимание, все почему-то подумали, что я очень сильно люблю получать отсортированные селекты из временных таблиц, не указывая при этом order by... Ну что ж поделаешь? Сам я и виноват - слишком старательно "косил под дурачка"... :-)) 2 YellowMan на: ... на тестовой базе все было тип-топ, а вот на рабочей - каждый раз новые значения... Вот это как раз и есть - самая большая проблема всех наших "разработчиков на T-SQL" ("наших" - легко могу адресовать только своей конторе, но убежден - в стране таких тоже немало). Тестовый сервер, как правило - у каждого на локалке установлен, в нем и пользователя больше одного никогда не бывает, и сам он (пользователь-разработчик) - почти всегда SA (у многих часто - с пустым паролем, ай-яй-яй). И на таком тестовом сервере - иногда можно получить очень "интересные" результаты, а на боевом - обломиться... 2 Всем на: Рушится вера в Каюсь, упростил я и исказил - реальные проблемы, которые возникли в рабочей процедуре, чем и вызвал - "поток непонимания". Ну раз уж пошел серьезный разговор - расскажу, что было на самом деле: Процедура та злосчасная - формировала временную табличку из строки начального сальдо по некоторым операциям из многих таблиц, потом - добавляла туда приходы и расходы за период из многих же таблиц, и в конце - добавляла строку конечного сальдо. Побочной задачей было - во временной таблице расчитать "набегающее сальдо" в порядке возрастания дат приходов и расходов. Делалось это без использования курсора, типа так: Код: plaintext 1. 2. Понятно, что для такого UPDATE - важен порядок перебора строк при сканировании таблицы (чтобы получить правильное "набегающее сальдо"). В версии 6.5 использовать хинты на индексы у временной таблицы - у меня не получилось: Код: plaintext 1. 2. 3. 4. 5. 6. 7. Пришлось ограничиться - простым созданием кластерного индекса без хинтов в UPDATE (пока - работает): Код: plaintext 1. 2. Вряд ли кто-нибудь станет спорить о том, что порядок перебора строк в UPDATE и в SELECT без ORDER BY - чем-то друг от друга отличаются? Вот поэтому-то и родился - "выморочный" примерчик из "рухнувшей Веры"... Извините за беспокойство. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
03.09.2002, 13:42:36
|
|||
|---|---|---|---|
|
|||
Возвращение рухнувшей Веры |
|||
|
#18+
2YellowMan "Т.е. Вы думаете, что select top 1 * from Ords order by OrderID desc прочтет только последнюю страницу с диска?" Вах. Канэшн. Вы же видите, что в кэше болтается только она (ну плюс еще 3 индексных стр-цы, по к-м он к ней спускался, но у них m_indexId = 2). Если Вы сомневаетесь, что она это действительно она, сделайте dbcc page('Northwind', 1, 97427, 1) и посмотрите последний заполненный слот: Slot 36, Offset 0x1b5e ---------------------- Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS 1D44BB5E: 003a0030 00002b45 00410052 00540054 0.:.E+..R.A.T.T. 1D44BB6E: 00010043 00000000 8c4f0000 00000000 C.........O..... 1D44BB7E: 8c6b0000 00000000 00000000 00020000 ..k............. 1D44BB8E: 4d340000 00000001 000e0000 00060020 ..4M........ ... 1D44BB9E: 009e0080 00b800b4 00c800c2 00610052 ............R.a. 1D44BBAE: 00740074 0065006c 006e0073 006b0061 t.t.l.e.s.n.a.k. 1D44BBBE: 00200065 00610043 0079006e 006e006f e. .C.a.n.y.o.n. 1D44BBCE: 00470020 006f0072 00650063 00790072 .G.r.o.c.e.r.y. 1D44BBDE: 00380032 00370031 004d0020 006c0069 2.8.1.7. .M.i.l. 1D44BBEE: 006f0074 0020006e 00720044 0041002e t.o.n. .D.r...A. 1D44BBFE: 0062006c 00710075 00650075 00710072 l.b.u.q.u.e.r.q. 1D44BC0E: 00650075 004d004e 00370038 00310031 u.e.N.M.8.7.1.1. 1D44BC1E: 00550030 00410053 0.U.S.A. 0x2b45 это как раз 11077 = значение OrderID в последней записи таблицы Ords. Ваш вариант с max(OrderID) действительно не годится, но по другой причине, чем предполагаете Вы. Просто при наличии индекса он возьмет его с индексной странички и не полезет в данные. Поэтому вы увидите в кэше только три индексных странички. А в отсутствие индекса он, наоборот, должен будет прочитать все, чтобы определить max(OrderID), поэтому в кэше после этого будут сидеть все страницы таблицы, а не только последняя, к-я нам нужна. Почему SQL Server не берет ее первой несмотря на то, что она в кэше, а остальные на диске? Ну все очень просто. В данном случае ему нужно прочесть всю таблицу. В кэш она заведомо ложится, поэтому он ее всю туда и засасывает за исключением последней страницы, которая там уже есть и которая просто становится более MRUшной. В связи с этим появляются еще две интересных задачи. Что будет происходить, если таблица в кэш не помещается? Счастливые обладатели 6.х могут просто увеличить долю процедурного кэша при пом. sp_configure, в SQL Server 7.0 и выше баланс определяется динамически, поэтому придется придумать что-нибудь похитрее. И вторая задача (копирайт шефа) - сохранится ли порядок выдачи страниц, если для чтения таблицы SQL Server применяет параллельный план? 2qu-qu Ну такие, скорее, философские рассуждения по поводу целесообразности несколько более глубокого, нежели дает документация, понимания предмета. Я не знаю, не уверен, нужно ли призывать к этому стремиться. Не требуется же от водителя досконального знания устройства автомобиля. Как и любой инструмент, SQL Server предназначен для решения вполне конкретных задач, и вполне достаточно, если человек, который им рулит, будет знать, как этого достичь. Ну вот были ткачи, досконально познавшие секреты ткацкого мастерства. История учит, что победа остается за мануфактурами, за централизованным массовым производством. Именно поэтому Oracle, для нормальной работы которого администратор должен был знать массу фенечек и нюансов настройки, стал проигрывать SQL Server. Пусть опытный админ мог решить задачу лучше и оптимальней, чем было заложено в алгоритмы динамической конфигурации SQL Server 7.0, но фишка в том, что он худо-бедно умел справляться с этим сам с минимальным участием DBA. Вероятно, мы слишком обожествляем ту область, в которой варимся. Все программирование в целом - не более чем средство автоматизации задач бизнес-логики. Поэтому машинные коды сменились ассемблерами, те - высокоуровневыми языками программирования и т.д. На смену C++ пришел C# с автоматической сборкой мусора и другими наворотами. Нет слов, С++ много гибче в плане управления памятью, но человек есть человек - забыл освободить объект и готова утечка памяти. Поди найди ее потом, когда это погребено под тоннами кода. Т.е. требуется держать в голове не только цель (бизнес-логику), но и специфичные вещи более низкого уровня. Конечно, программист на С++ прекрасно разберется и с C#, знания лишними не бывают. Его низкоуровневые знания дадут ему возможность не только более быстро освоить, но и писать более красивые программы. Но он растворится в лавине новичков, которым просто не нужны его знания, чтобы добиваться цели при помощи нового инструмента. (Пусть и несколько коряво с точки зрения патриарха). Мораль: мы с Вами - динозавры и вымрем в скором времени к чертовой матери. Не то, чтобы я слишком испереживался по этому поводу (против эволюции не попрешь), так - слегка выплеснуть эмоции. Не взыщите. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
03.09.2002, 14:11:20
|
|||
|---|---|---|---|
Возвращение рухнувшей Веры |
|||
|
#18+
Можно я тоже побрюзжу немного ? Ну не верю я, что страничка, прочитанная в буфер - последняя. Последняя относительно чего ? Порядка записи ? Почему не третья от начала ? Я не претендую на знание всего и вся, но так как я себе представляю работу оптимизатора - в случае max(), как Вы правильно заметили, значение возьмтся из индекса, а в случае top 1 - будет прочитана вся страница где этот max() есть и отсортирована. Почему - вопрос к писателям оптимизатора. Наверное есть причины. Я, кстати, MAX(OrderID) написал только для того, чтобы не писать select top 1 ..order by , бо для меня это одно и то же. А насчет неправильного порядка - так все очень просто. На тестовой машине всегда тишь и гладь, только я камешки покидываю иногда, кеш там с рестарта так и не обновлялся никогда. А на боевом - несколько десятков инсертов в секунду, 50 юзарей с отчетами, а на таблице кластерный индекс, составной, и инсерты не всегда последовательно по индексу, мать их ! , вот и имеем сплиттинг по полной программе и в кеше такую кашу, что ни Б-г, ни черт, ни оптимизатор не разберется. Утрирую конечно. У меня вот какая беда - я нить беседы потерял :( Мы о чем спорим ? Можно ли делать select без order by, если данные при вставке были отсортированы ? Или как устроен оптимизатор в 2К ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
03.09.2002, 14:33:47
|
|||
|---|---|---|---|
Возвращение рухнувшей Веры |
|||
|
#18+
Опс ! Прошу пардона, поторопился с ответом. Вот здесь В данном случае ему нужно прочесть всю таблицу. В кэш она заведомо ложится, поэтому он ее всю туда и засасывает за исключением последней страницы, которая там уже есть и которая просто становится более MRUшной речь идет о select * from tbl ? Если так, прошу прощения, не разобрался, конечно он прочтет ее всю кроме нужной, не последней :), страницы. И выдаст как читал. Т.е. если есть кластерный индекс - по порядку, если в кеше есть место и если в таблицу не вставляется ничего, и если нет сплиттинга и если нет еще кучи чего...но строить на этом решение - я уж лучше курсором :(( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
03.09.2002, 17:36:24
|
|||
|---|---|---|---|
Возвращение рухнувшей Веры |
|||
|
#18+
2 YellowMan на: ... У меня вот какая беда - я нить беседы потерял :( Мы о чем спорим ? Да мы уже и не "спорим", вроде? Спорили как раз - в первой "рухнувшей вере", т.к. слишком много там было - "уверенных в себе профессионалов"... :-)). и на: ... но строить на этом решение - я уж лучше курсором :(( Курсоры тоже, ведь (в MS-SQL) - не эталон стабильности и надежности работы... (даже в новейшей его версии). Вот поэтому и обсуждаем - что можно использовать чтобы "строить на этом решение", а что - не стоит? Я так понял, что вы - не рекомендуете использовать даже кластерный индекс, если нет уверенности, что записи во временную таблицу будут попадать в его порядке? А как тогда насчет хинтов в UPDATE? (которые, вроде бы, согласно той же BOL - должны работать...). К сожалению - не могу счаз прямо проверить на SQL2K, но на SQL6.5 - меня жестоко по этому поводу "обломили", как уже было упомянуто выше... В конце-концов - моя задача нахождения "набегающего сальдо" - действительно побочная, при необходимости я ее могу легко перенести "на клиента" и - перестать морочить вам всем голову... :-)) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
04.09.2002, 14:44:22
|
|||
|---|---|---|---|
Возвращение рухнувшей Веры |
|||
|
#18+
Я подхожу к этому вопросу очень жестко - если написано нельзя, значит нельзя - потом уже можно для себя выяснить почему, если есть желание и время. BOL, он как устав караульной службы - писан не зря. Кстати вопрос, а что будет если не хватит кеша весьма интересен. Я думаю, кеш никогда не кончиться - зря ли lazywriter хлеб ест ? А Вы что думаете ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|

start [/forum/topic.php?fid=46&tablet=1&tid=1820624]: |
0ms |
get settings: |
5ms |
get forum list: |
13ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
44ms |
get topic data: |
8ms |
get forum data: |
2ms |
get page messages: |
42ms |
get tp. blocked users: |
1ms |
| others: | 220ms |
| total: | 339ms |

| 0 / 0 |
