Tertium |
Отправлено: 11.07.2005, 13:09 |
|
Машинист паровоза
Группа: Почетный участник
Сообщений: 192
|
Сервер MSSQL2k. Цепляюсь TADOConnection + TADOQuery.
у меня есть громадная таблица — записей 100000-1000000. В ней [int][int][datetime][varchar]. Задача выводить её в гриде, но при этом идентифицировать для юзера непонятные ему значения интов (1 — "событие открытия двери", 2 — "событие выключения аппарата" и тд), даты выводить разбивая на две колонки (дата и время), а из varchar выводить первые 100 символов и ставить многоточие.
Короче, использовать DBGrid нельзя, поскоку надо каждую запись немного видоизменять перед выводом.
А просто загрузить select * в грид не могу — слишком ровсет огромный. Вывод такой: надо запросом брать в 2-3 раза больше чем на странице умещается, затем по мере скрлллирования подгружать. Но не охота руками это делать. Может есть способ делать это как DBGrid, но подменив метод отображения в грид данных? Там-то эта логика вывода больших ровсетах уже реализована. Ктонть пробовал наследовать DBGrid в таком аспекте? Или может есть ещё какие пути решения задачи?
|
|
AVC |
Отправлено: 11.07.2005, 13:26 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
QUOTE |
Короче, использовать DBGrid нельзя, поскоку надо каждую запись немного видоизменять перед выводом.
|
Заблуждаетесь. Еще как можно.
QUOTE |
А просто загрузить select * в грид не могу — слишком ровсет огромный
|
Правильно. И не ненадо его грузить. Пожалейте пользователя.
Общее правило — ограничивать размер выборки как можно раньше. Может стоит изменить постановку задачи? Зачем пользователю показывать весь 1 000 000 записей? Все равно больше сотни он просто не воспримет. Может стоит подумать об "условиях отбора"? |
|
greyich |
Отправлено: 11.07.2005, 15:42 |
|
Не зарегистрирован
|
самое простое и как я понимаю самое легкое — отдать все вычисления на растерзание sql-server'у. На то он и сервер чтобы это всё обработать. Предлагаю использовать представления (пользователь и не догадается что это не таблица). что-то примерно так
select int1, ext_int1 = case ext_int1 when '1' then 'событие открытия двери', when '2' then 'событие выключения аппарата' end, date1 = date(dateTime1), time1 = (datetime1) from table1
текст писался прям в браузере без проверки, если что юзай books online |
|
Guest |
Отправлено: 11.07.2005, 15:57 |
|
Не зарегистрирован
|
2AVC: в том-то и засада, что юзер хочет мочь видеть любую часть ровсета. Он конечно задаёт условия начальные (за период с _ по _), но ведь может задать ваще с 1900 до 2100.
2greyich: интересная мысль, логично
|
|
Gedeon |
Отправлено: 11.07.2005, 16:57 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
QUOTE (greyich @ 11/07/2005, 15:42) | select int1, ext_int1 = case ext_int1 when '1' then 'событие открытия двери', when '2' then 'событие выключения аппарата' end, date1 = date(dateTime1), time1 = (datetime1) from table1
|
А не проще ли как все нормальные люди сделать связанную таблицу и выбирать из нее, да и побыстрее будет и перечислять не надо, а по поводу первых символов SUBSTR поможет?
|
|
Tertium |
Отправлено: 11.07.2005, 17:14 |
|
Машинист паровоза
Группа: Почетный участник
Сообщений: 192
|
2Gedeon: да это уже детали. самая фишка была в представлении. мне чото в голову сразу не пришло. вот промежуточный результат:
SQL | select (LTRIM(RTRIM(STR(datepart(yy,last_query))))+'[color=orange]-'[/color]+
LTRIM(RTRIM(STR(datepart(mm,last_query))))+'[color=orange]-'[/color]+
LTRIM(RTRIM(STR(datepart(dd,last_query)))) ) as 'дата',
(LTRIM(RTRIM(STR(datepart(hh,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(n,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(ss,last_query)))) ) as 'время',
place_no as 'номер места',
club_id as 'ID зала',
(case event_id
when 1 then 'открытия двери'
when 2 then 'закрытие двери'
when 3 then 'очистка бухгалтерии'
when 4 then 'включение'
when 5 then 'выключение'
when 6 then 'смена платы'
ELSE 'неизвестное событие'
end) as 'тип события'
from Events order by last_query desc |
работает с десятитысячной таблицей ваще незаметно.
кстати вот это уродство:
(LTRIM(RTRIM(STR(datepart(hh,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(n,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(ss,last_query)))) ) as 'время'
по человечески возможно написать под mssql? А то функций date и time в нём нету...
PS: ну не ругайтесь, сделал связанную таблицу
Отредактировано Tertium — 11/07/2005, 17:48
|
|
avc* |
Отправлено: 11.07.2005, 17:19 |
|
Не зарегистрирован
|
QUOTE |
2AVC: в том-то и засада, что юзер хочет мочь видеть любую часть ровсета. Он конечно задаёт условия начальные (за период с _ по _), но ведь может задать ваще с 1900 до 2100.
|
Он (user) предупрежден, что чем шире диапазон, тем дольше ждать? Начинаем показ с опроса диапазона. Хочет видеть много, пусть платит временем.
Select и View в вашем случае это одно и тоже и, естественно, подготовку данных должен делать сервер (это я даже не оговаривал, а о возможностях грид — просто замечание, если меня не так поняли ).
Пока писал ответ он уже устарел.
Отредактировано AVC — 11/07/2005, 16:21 |
|
Guest |
Отправлено: 11.07.2005, 20:45 |
|
Не зарегистрирован
|
всё, убрал нахрен связанную таблицу. С ней-то конечно прикольней запрос выглядит , но скорость выполнения select'а по 10000 записей — 7 секунд. С case...when...then — 1 секунда. Так что...
|
|
Tertium |
Отправлено: 11.07.2005, 21:07 |
|
Машинист паровоза
Группа: Почетный участник
Сообщений: 192
|
тьфу блин. с фаером перемутил — не авторизовал сайт
|
|
olegenty |
Отправлено: 12.07.2005, 07:02 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
QUOTE (Guest @ 11/07/2005, 21:45) | всё, убрал нахрен связанную таблицу. С ней-то конечно прикольней запрос выглядит , но скорость выполнения select'а по 10000 записей — 7 секунд. С case...when...then — 1 секунда. Так что... |
а как же индексы?
|
|
Tertium |
Отправлено: 12.07.2005, 23:22 |
|
Машинист паровоза
Группа: Почетный участник
Сообщений: 192
|
а что индексы? видимо никак. есть но не помогают видимо. может, конечно я делаю неправильно, но:
SQL | CREATE TABLE [Events] (
[id] [int] IDENTITY (1, 1) NOT NULL ,
[event_id] [int] NOT NULL DEFAULT (0),
[place_no] [tinyint] NOT NULL DEFAULT (0),
[club_id] [int] NOT NULL DEFAULT (0),
[last_query] [datetime] NOT NULL DEFAULT GETDATE(),
PRIMARY KEY CLUSTERED
(
[id]
)
)
CREATE TABLE [event_names] (
[event_id] [int] NOT NULL ,
[event_name] [char] (255) COLLATE Cyrillic_General_CI_AS NOT NULL ,
PRIMARY KEY CLUSTERED
(
[event_id]
)
)
|
SQL | select bla bla bla from events,event_names where events.event_id=event_names.event_id order by bla bla bla |
10000 = 7 sec
SQL | select bla bla (case (event_id)
when 1 then 'идём на фиг'
when 2 then 'продолжаем идти'
when 3 then 'идём на фиг до конца'
end) as 'имя события' from events |
10000 = 1 sec
как ещё мона написать с таблицей-словарём?
|
|
olegenty |
Отправлено: 13.07.2005, 07:01 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
индекс должен быть ещё и по bla-bla-bla, раз уж сортируешь...
|
|
Tertium |
Отправлено: 13.07.2005, 15:47 |
|
Машинист паровоза
Группа: Почетный участник
Сообщений: 192
|
не поленился, пересоздал таблицы, сделал индекс Events сначала одновременно по двум полям, по каким идёт сортировка, потом по каждомук полю в отдельности. тот же результат в обоих случаях. 7 секунд. против 1 с case. так что bla или не bla, а волшебства не произошло
Отредактировано Tertium — 13/07/2005, 15:48
|
|
Gedeon |
Отправлено: 13.07.2005, 17:13 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
Не должно такого быть!
Завтра смоделирую ситуацию, проверю, расскажу.
|
|
greyICH |
Отправлено: 13.07.2005, 18:42 |
|
Не зарегистрирован
|
конечно ждем результатов, но ИМХО запрос на лету формирующий данные из одной таблицы должен работать быстрее, чем сцепление 2-х таблиц.
кроме того места занимает меньше (это если использовать хранимую процедуру) и его гораздо проще изменить если что-то необходимо поменять ) например изменились правила вывода и цифрам будут соответствовать другие значения — написать еще одну хранимую процедуру дело одной минуты, а если её текст генерить на клиенте, то можно динамически формировать запрос под конкретную ситуацию.
ЗЫ: только не считайте, что я кидаю камни в чей-то огород. очень уважаю мнение Gedeon и olegenty (в bookmarks!!!!) |
|
Guest |
Отправлено: 13.07.2005, 22:06 |
|
Не зарегистрирован
|
2greyICH: присоединяюсь насчёт того,что "запрос на лету формирующий данные из одной таблицы должен работать быстрее, чем сцепление 2-х таблиц. "
плюс вариант с case позволяет отловить и те записи в которых событие имеет неизвестный науке вид а такое возможно, никогда не знаешь, что электронщикам в голову придёт:)
2Gedeon: код в помощь
создание
SQL | create database gambling
go
use gambling
go
CREATE TABLE [Events] (
[id] [int] IDENTITY (1, 1) NOT NULL ,
[event_id] [int] NOT NULL DEFAULT (0),
[place_no] [tinyint] NOT NULL DEFAULT (0),
[club_id] [int] NOT NULL ,
[last_query] [datetime] NOT NULL DEFAULT (getdate()),
PRIMARY KEY CLUSTERED
(
[id]
)
)
GO
CREATE INDEX [my_fucking_index] ON [Events]
(
[last_query] desc,
[club_id] asc )
go
CREATE TABLE [event_names] (
[event_id] [int] NOT NULL ,
[event_name] [char] (255) COLLATE Cyrillic_General_CI_AS NOT NULL ,
PRIMARY KEY CLUSTERED
(
[event_id]
)
)
GO
insert into event_names (event_id,event_name) values(1,'открытие двери')
insert into event_names (event_id,event_name) values(2,'закрытие двери' )
insert into event_names (event_id,event_name) values(3,'очистка бухгалтерии')
insert into event_names (event_id,event_name) values(4,'включение')
insert into event_names (event_id,event_name) values(5,'выключение')
insert into event_names (event_id,event_name) values(6,'смена платы')
|
заполнение (условно)
CODE |
for (int i=0;i<10000;i++)
{
DataBase.exec(AnsiString().sprintf("insert into events(event_id, place_no, club_id, last_query) values(%d,%d,%d, '%s')",
rand()%6+1,rand()%127+1,rand()%10,(TDateTime::CurrentDateTime()+rand()%100).FormatString("yyyy-mm-dd hh:nn:ss")));
}
|
селекты:
1. с case
SQL | select (LTRIM(RTRIM(STR(datepart(yy,last_query))))+'-'+
LTRIM(RTRIM(STR(datepart(mm,last_query))))+'-'+
LTRIM(RTRIM(STR(datepart(dd,last_query)))) ) as 'Дата',
(LTRIM(RTRIM(STR(datepart(hh,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(n,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(ss,last_query)))) ) as 'Время',
place_no as 'Номер места',
club_id as 'ID зала',
(case event_id
when 1 then 'открытия двери'
when 2 then 'закрытие двери'
when 3 then 'очистка бухгалтерии'
when 4 then 'включение'
when 5 then 'выключение'
when 6 then 'смена платы'
ELSE 'неизвестное событие'
end) as 'Событие'
from Events order by last_query desc, club_id |
по связанным таблицам:
SQL | select (LTRIM(RTRIM(STR(datepart(yy,last_query))))+'-'+
LTRIM(RTRIM(STR(datepart(mm,last_query))))+'-'+
LTRIM(RTRIM(STR(datepart(dd,last_query)))) ) as 'Дата',
(LTRIM(RTRIM(STR(datepart(hh,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(n,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(ss,last_query)))) ) as 'Время',
place_no as 'Номер места',
club_id as 'ID зала',
event_name as 'Событие'
from Events,event_names where Events.event_id=event_names.event_id order by last_query desc, club_id |
Насчёт последнего запроса: связывать таблицы можно только так, или как ещё?..
|
|
Tertium |
Отправлено: 13.07.2005, 22:11 |
|
Машинист паровоза
Группа: Почетный участник
Сообщений: 192
|
да чтоб этот файрвол!!! Предыдущий пост считать моим
|
|
AVC |
Отправлено: 14.07.2005, 08:37 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
Немного статистики по Oracle (если интересно)
Исходные данные — таблица из работающей системы 17 полей 2`341`428 записей.
Выполнение запросов на count или получение нескольких первых строк дают примерно одинаковый результат менее 1 сек. Поэтому для замеров открывался курсор и "фетчились" все записи результата.
Итак времена
Просто проход по таблице — 65 сек
Рашифровка ID функцией — 199 сек
Расшифровка связью двух таблиц — 102 сек
Аналог case — 69 сек
PS. Замеры проводились на работающей системе и во время эксперимента в таблицу заносились данные с других станций.
|
|
Tertium |
Отправлено: 14.07.2005, 09:44 |
|
Машинист паровоза
Группа: Почетный участник
Сообщений: 192
|
вот и я говорю
|
|
Gedeon |
Отправлено: 14.07.2005, 14:18 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
Итак, что получилось у меня:
Сервер: CELERON 1000, 256 MB RAM.
Microsoft SQL Server 2000 — 8.00.194
CODE |
CREATE TABLE [dbo].[TST_SELECT_SPEED] (
[ID] [int] IDENTITY (1, 1) NOT NULL ,
[EVENT_ID] [int] NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[TST_SELECT_SPEED] WITH NOCHECK ADD
CONSTRAINT [PK_TST_SELECT_SPEED] PRIMARY KEY CLUSTERED
(
[ID]
) ON [PRIMARY]
GO
CREATE INDEX [SPEED] ON [dbo].[TST_SELECT_SPEED]([EVENT_ID]) ON [PRIMARY]
GO
CREATE TABLE [dbo].[TST_DESCR] (
[ID] [int] IDENTITY (1, 1) NOT NULL ,
[Descr] [varchar] (50) COLLATE Cyrillic_General_CI_AS NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[TST_DESCR] WITH NOCHECK ADD
CONSTRAINT [PK_TST_DESCR] PRIMARY KEY CLUSTERED
(
[ID]
) ON [PRIMARY]
GO
|
Заполняем
CODE |
DECLARE @COUNTER AS INT
SET @COUNTER = 0
WHILE (@COUNTER<1000000)
BEGIN
INSERT INTO dbo.TST_SELECT_SPEED (EVENT_ID) VALUES ((CAST(RAND()*5)+1 AS INT))--Random_Number
SET @COUNTER = @COUNTER + 1
END |
Ну и выгребаем записи
CODE |
SELECT dbo.TST_SELECT_SPEED.ID, dbo.TST_DESCR.Descr
FROM dbo.TST_DESCR INNER JOIN
dbo.TST_SELECT_SPEED ON
dbo.TST_DESCR.ID = dbo.TST_SELECT_SPEED.EVENT_ID
--ORDER BY dbo.TST_SELECT_SPEED.ID |
8 секунд, с сортировкой 12
Второй способ
CODE |
select dbo.TST_SELECT_SPEED.ID,
(case dbo.TST_SELECT_SPEED.EVENT_ID
when 1 then 'открытия двери'
when 2 then 'закрытие двери'
when 3 then 'очистка бухгалтерии'
when 4 then 'включение'
when 5 then 'выключение'
end) as 'Событие'
FROM dbo.TST_SELECT_SPEED
--ORDER BY dbo.TST_SELECT_SPEED.EVENT_ID |
8 секунд, с сортировкой 8 секунд
Я удивлен .
Ну и сортировка по dbo.TST_SELECT_SPEED.EVENT_ID в обоих случаях дает 8 секунд.
Т.е. никакой семикратной разницы нет! При 1000000 записей результаты одинаковы. По поводу увеличения времени при связанных таблицах с сортировкой по первичному ключу я вообще не понял, надо подумать.
Таблицы простейшие, но это-то и правильно при таком сравнении, надо будет усложнить, проверить результат.
Поэтому считаю связанные таблицы более удобными для практического применения, в этом случае элементарно дополнить изменить справочник, сделайте то же с ХП, если юзер ниче не понимает в сервере или ему туда нельзя.
|
|
Tertium |
Отправлено: 14.07.2005, 15:14 |
|
Машинист паровоза
Группа: Почетный участник
Сообщений: 192
|
я выложил код выше и настаиваю на семикратной разнице. не раз проверял. тестил в родном его Query Analizer. Неужели это из-за пропущенного INNER JOIN??? или это из-за того, что у меня SQLServer стоит на Win2k3 прикрытый 4 сервиспаком? Без SP он вообще не работал.
и как быть в варианте со связанными таблицами с описанным выше случаем, когда возможно неизвестное событие, и его надо выводить?
Отредактировано Tertium — 14/07/2005, 15:19
|
|
greyICH |
Отправлено: 14.07.2005, 16:00 |
|
Не зарегистрирован
|
уважаемый Gedeon, как мне кажется дает более универсальный способ решения, подходящий к любой проблеме данного рода. спорить в данном случае не решусь.
2Tertium: вообщем вам предложили 2 варианта решения — вам и выбирать. вполне может быть участвуют факторы, которые Вы не замечаете и потому решение будет в любом случае субъективным |
|
Gedeon |
Отправлено: 14.07.2005, 16:02 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
В точности повторил Ваш код, 10000 записей результат
Связанные таблицы ~700 mS
case ~650 mS
с сортировкой
Связанные таблицы ~550 mS
case ~450 mS
без сортировки
2. Использовать OUTER JOIN
|
|
Gedeon |
Отправлено: 14.07.2005, 16:17 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
И еще очень настоятельно рекомендую Вам присмотреться к 1 посту AVC в этом топике, не выбирайте все записи, сделайте юзеру
TOP 100, TOP 10 PERCENT на худой конец, и отлавливайте перемещение на последнюю запись, а там если нужно уже тащите больше записей, поскольку при таком количестве вопрос времени упирается в вопрос доставки данных на клиента, а не обработки сервером, поэтому выиграть что-то тяжело.
НЕ НУЖНЫ ЮЗЕРУ ВСЕ ЗАПИСИ, он их не в состоянии проанализировать ну никак, тут можно задуматься над функциональностью программы, че-то ему добавить, чтоб унялся .
|
|
Tertium |
Отправлено: 15.07.2005, 02:02 |
|
Машинист паровоза
Группа: Почетный участник
Сообщений: 192
|
2Gedeon
не совсем понимаю такие маленькие цифры у меня P-IV 2.6GHz 1GB RAM Win2k3 sp1 MSSQL2k sp4 и при этом я получаю в лучшем случае 1000мс... А у Вас на целероне, значит, 650-700 мс...
Не поленился ещё раз. Проверил. Приводить здесь запросы не буду, скажу только, что переписал с простого t1.id=t2.id на явный иннерджойн, как у вас. Те же 10000 несчастных записей. Ну и те же 8 секунд с сортировкой, 7 — без. Опять же, с case — 1 секунда.
Может быть тут играет роль тестовый кортеж? Да не думаю, тем более что код его генерации я приводил, и вы его вроде повторили.
Повторил с миллионом:
в таблице: индекс на event_id, индекс на {last_query desc, club_id asc} — как в order by.
Да, добрая шутка — WHILE (@COUNTER<1000000) ) Я успел кофе сварить и выпить (12:07)
case с сортировкой — 11сек
case без сортировки — 8 сек
inner join/left outer join без сортировки — приблизительно разброс 43-50 секунд
inner join/left outer join с сортировкой — 3мин 30сек.
Вот так вот.
Я, кстати, понял, у меня большую часть запроса выполнялось раньше преобразование даты-времени через LTRIM(RTRIM(STR(datepart(…)))). Выше показаны результаты с закомментаренным монстром (с млн записей).
Но даже не в преобразовании даты дело — разрыв всё равно велик (8 и 45).
Кстати спор-то пошёл изначально не из-за того, во сколько раз inner join выполняется медленнее, а из-за того, выполняется ли он медленнее вообще. И даже в Ваших результатах case опережает.
Никого не хочу обидеть, но я же не саботирую результаты:)
Да не нужны, не нужны юзеру все записи, не спорю.
Ограничения есть, и по периоду, и по группе машин, даже можно конкретные машины галочками выбирать. НО: юзер теоретически МОЖЕТ затребовать весь ровсет (проставить дикие условия отбора). Даже если и так, он отдастся ему не весь сразу — именно для того мы и используем TDBGrid. Запрос делается как я понимаю "с сих по сих", где "сих" — размер экрана по вертикали:) И так при каждом перетягивании ползунка. Так что не беспокойтесь за юзера, не захлебнётся он
2greyICH. Я и так выбрал с первого Вашего поста способ с case. И, кстати, до сих пор не понял, как обрабатывать неизвестное событие в случае не с case’ом. Не, запрос-то написать можно, так ведь он будет тормозный, и, если честно, даже напрягаться не хочется, настолько лаконично всё получается case’ом. Способ со связанными таблицами выглядит поцивилизованней, но так удобен и универсален для данной ситуации. Да и к тому же (по крайней мере, у меня на машине) сильно уступает в скорости.
2all. Есть мнение, что стоит тему закрыть. Всем спасибо за бурную дискуссию. Побольше бы таких интересных тем. Хотя если кто-то что-то хочет сказать, милости просим:)
|
|
Gedeon |
Отправлено: 15.07.2005, 08:40 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
QUOTE (Tertium @ 15/07/2005, 02:02) | Те же 10000 несчастных записей. Ну и те же 8 секунд с сортировкой, 7 — без. Опять же, с case — 1 секунда.
Может быть тут играет роль тестовый кортеж? Да не думаю, тем более что код его генерации я приводил, и вы его вроде повторили.
Повторил с миллионом:
в таблице: индекс на event_id, индекс на {last_query desc, club_id asc} — как в order by.
Да, добрая шутка — WHILE (@COUNTER<1000000) ) Я успел кофе сварить и выпить (12:07)
case с сортировкой — 11сек
case без сортировки — 8 сек
inner join/left outer join без сортировки — приблизительно разброс 43-50 секунд
inner join/left outer join с сортировкой — 3мин 30сек.
Вот так вот.
Я, кстати, понял, у меня большую часть запроса выполнялось раньше преобразование даты-времени через LTRIM(RTRIM(STR(datepart(…)))). Выше показаны результаты с закомментаренным монстром (с млн записей).
|
Не, не, не не спешите закрывать, для 10000 записей 8 секунд? Разбирайтесь с сервером, что-то не то, такое кол-во записей для SQL Server — это ерунда. Я проверял на 10000 записей полностью скопировав запрос, у Вас такие времена огромные, что-то явно не то с сервером, план запроса посмотрите, время с case у нас одинаковое, и похоже упирается в тот же транспорт — 8 секунд, поэтому я явно подозреваю что-то с сервером, кстати на испытываемой мною машине крутится серверная часть клиент-банка, плюс батники каждые 5 минут криптуют файлы, так что Вам есть над чем задуматься.
Если будет затишье на основном сервере попробую там (2хР4 2 ГБ ОЗУ + RAID6).
Отредактировано Gedeon — 15/07/2005, 08:47
|
|
olegenty |
Отправлено: 15.07.2005, 09:02 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
SQL | select c.*
from dbo.Cycle c
inner join dbo.Action a on c.ActionID = a.ActionID
order by a.ActionTypeID
|
проверил у себя вот на таком запросе.
в таблице dbo.Cycle — 574958 записей. в таблице dbo.Action — 7 записей, где присутствует 5 типов ActionTypeID
запускалось на работающем сервере (статистику не посмотрел, но десятки транзакций/сотни инструкций в секунду реально делает, только вчера ХП отлаживал, профайлер ни на секунду не останавливается в выводе).
время выполнения 8-10 сек
если написать top 10000, то время выполнения 0 сек., top 50000 — 1 сек., top 100000 — 2 сек., top 150000 — 2-3 сек...
так что если не отдавать пользователю больше нескольких сотен записей (а нафига ему больше?), то можно сказать, что всё работает мгновенно.
|
|
Tertium |
Отправлено: 15.07.2005, 11:58 |
|
Машинист паровоза
Группа: Почетный участник
Сообщений: 192
|
2Gedeon: Вы жеговорили, что повторили мой код полностью. Я в предыдущем посте: 8 секунд это из-за шестикратного LTRIM(RTRIM(STR(datepart(…)))). Наверно, вы такую дурацкую строчку в запрос не вставляли (кстати, как всё-таки ещё можно отделить дату от времени?).
Могу сделать предположение, почему разница была аж в 7-8 раз: может быть, работая с одной таблицей, сервер кэшировал строковые функции (что бы это ни значило:)), а когда с двумя работал — нет. Хотя и на миллионе 8 к 45.
Убрав LTRIM(RTRIM(STR(datepart(…)))), я получил с 10000 промежутки времени меньше секунды.
Query Analizer показывает время в секундах, поэтому я повысил точность, сделав 1 млн записей. Результаты уже не замутнённые строковыми функциями:
case с сортировкой — 11сек
case без сортировки — 8 сек
inner join/left outer join без сортировки — приблизительно разброс 43-50 секунд
inner join/left outer join с сортировкой — 3мин 30сек.
разбег времени с join (с сортировкой и без) ставит меня в тупик.
2olegentry: мой запрос несско тяжелее select* изза перегруженности строковыми функциями. НO: он не выполняется полностью в реальной среде, как я уже неоднократно писал. Поэтому не нужно top. Здесь мы тестируем запросы на скорость уже чисто академически
PS: что есть всё-таки ХП в этом контексте?
Так, ещё раз выкладываю весь код, пробуйте у себя AS IS.
создание:
SQL | Create database gambling
go
use gambling
go
CREATE TABLE [dbo].[Events2] (
[id] [int] IDENTITY (1, 1) NOT NULL ,
[event_id] [int] NOT NULL DEFAULT (0),
[place_no] [tinyint] NOT NULL DEFAULT (0),
[club_id] [int] NOT NULL DEFAULT (0),
[last_query] [datetime] NOT NULL DEFAULT (getdate())
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[event_names] (
[event_id] [int] NOT NULL ,
[event_name] [char] (255) COLLATE Cyrillic_General_CI_AS NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Events2] WITH NOCHECK ADD
PRIMARY KEY CLUSTERED
(
[id]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[event_names] WITH NOCHECK ADD
CONSTRAINT [PK_event_names] PRIMARY KEY CLUSTERED
(
[event_id]
) ON [PRIMARY]
GO
CREATE INDEX [IX_Events2] ON [dbo].[Events2]([last_query] DESC , [club_id]) ON [PRIMARY]
GO
CREATE INDEX [IX_Events2_2] ON [dbo].[Events2]([event_id]) ON [PRIMARY]
GO
|
заполнение
SQL | use gambling
delete from Events2 go
DECLARE @COUNTER AS INT
DECLARE @club_id AS INT
DECLARE @place_no AS INT
DECLARE @event_id AS INT
SET @COUNTER = 0
WHILE (@COUNTER<1000000)
BEGIN set @club_id=rand()*1000
set @place_no=rand()*127
set @event_id=rand()*5
INSERT INTO Events2 (EVENT_ID, club_id, place_no, last_query)
VALUES (@event_id, @club_id, @place_no, GETDATE() )
SET @COUNTER = @COUNTER + 1
END
insert into event_names (event_id,event_name) values(1,'открытие двери')
insert into event_names (event_id,event_name) values(2,'закрытие двери' )
insert into event_names (event_id,event_name) values(3,'очистка бухгалтерии')
insert into event_names (event_id,event_name) values(4,'включение')
insert into event_names (event_id,event_name) values(5,'выключение')
insert into event_names (event_id,event_name) values(6,'смена платы')
insert into event_names (event_id,event_name) values(0,'неизвестное')
|
запрос с case:
SQL | use gambling
select /*(LTRIM(RTRIM(STR(datepart(yy,last_query))))+'-'+
LTRIM(RTRIM(STR(datepart(mm,last_query))))+'-'+
LTRIM(RTRIM(STR(datepart(dd,last_query)))) ) as 'Дата',
(LTRIM(RTRIM(STR(datepart(hh,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(n,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(ss,last_query)))) ) as 'Время',*/
place_no as 'Номер места',
club_id as 'ID зала',
(case event_id
when 1 then 'открытия двери'
when 2 then 'закрытие двери'
when 3 then 'очистка бухгалтерии'
when 4 then 'включение'
when 5 then 'выключение'
when 6 then 'смена платы'
ELSE 'неизвестное событие'
end) as 'Событие'
from Events2 --order by last_query desc, club_id |
запрос с inner join:
SQL | use gambling
select /*(LTRIM(RTRIM(STR(datepart(yy,last_query))))+'-'+
LTRIM(RTRIM(STR(datepart(mm,last_query))))+'-'+
LTRIM(RTRIM(STR(datepart(dd,last_query)))) ) as 'Дата',
(LTRIM(RTRIM(STR(datepart(hh,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(n,last_query))))+':'+
LTRIM(RTRIM(STR(datepart(ss,last_query)))) ) as 'Время',*/
place_no as 'Номер места',
club_id as 'ID зала',
event_name as 'Событие'
from Events2 inner JOIN event_names ON Events2.event_id = event_names.event_id
--order by last_query desc, club_id |
можете откомметарить блоки преобразования даты и глянуть, что на целероне будет
Отредактировано Tertium — 15/07/2005, 12:52
|
|
olegenty |
Отправлено: 15.07.2005, 13:27 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
теперь о применении функций...
так вот, функции ДОЛЖНЫ привенять В ПОСЛЕДНЮЮ очередь, когда выборка УЖЕ сделана и минимальна. я тоже наступал на такие грабли: применял функцию на "ядренном" view, который возвращает туеву хучу записей. увеличение производительности настало при выносе применения функций в ХП, когда выборка уже конкретизирована условиями. оч. помогло.
ХП — хранимая процедура.
|
|
Gedeon |
Отправлено: 15.07.2005, 13:27 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
Хочу Вас расстроить, я проверял именно с такими преобразованиями т.е. использовал ctrl+c, ctrl+v ничего не меняя, указанное время для этого случая, преобразования ничего не стоят.
|
|
|