powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Связанные списки
21 сообщений из 21, страница 1 из 1
Связанные списки
    #32065804
Snark
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сначала упрощенная структура базы данных :
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
CREATE TABLE [dbo].[A] ([AID] [int] NOT NULL ,[Name] [varchar] ( 50 ),[Country] [varchar] ( 50 )) ON [PRIMARY]
CREATE TABLE [dbo].[R]([RID] [int] NOT NULL ,[Title] [varchar] ( 50 ),[Journal] [varchar] ( 50 )) ON [PRIMARY]
CREATE TABLE [dbo].[R_A] ([AID] [int] NOT NULL ,[RID] [int] NOT NULL) ON [PRIMARY]
ALTER TABLE [dbo].[A] ADD CONSTRAINT [PK_A] PRIMARY KEY  CLUSTERED ([AID])  ON [PRIMARY] 
ALTER TABLE [dbo].[R] ADD CONSTRAINT [PK_R] PRIMARY KEY  CLUSTERED ([RID])  ON [PRIMARY] 
ALTER TABLE [dbo].[R_A] WITH NOCHECK ADD CONSTRAINT [PK_R_A] PRIMARY KEY  CLUSTERED([AID],[RID])  ON [PRIMARY] 
ALTER TABLE [dbo].[R_A] ADD CONSTRAINT [FK_R_A_A] FOREIGN KEY ([AID]) REFERENCES [dbo].[A]([AID]),
			    CONSTRAINT [FK_R_A_R] FOREIGN KEY ([RID]) REFERENCES [dbo].[R] ([RID])			    
			    
INSERT A VALUES ( 1 , 'A', 'A')
INSERT A VALUES ( 2 , 'B', 'B')
INSERT A VALUES ( 3 , 'C', 'C')
INSERT R VALUES ( 1 , '1', '1')
INSERT R VALUES ( 2 , '2', '2')
INSERT R VALUES ( 3 , '3', '3')
INSERT R_A VALUES ( 1 ,  1 )
INSERT R_A VALUES ( 1 ,  2 )
INSERT R_A VALUES ( 2 ,  1 )
INSERT R_A VALUES ( 2 ,  3 )
INSERT R_A VALUES ( 3 ,  3 )

User может выбирать произвольные значения из списков A.Country и B.Journal
после чего содержание списков обновляется с учетом сделанного выбора
Так как списки связанные, значения выбранные в одном списке влияют на содержание другого списка
Следовательно, чтобы обновить содержание списка с учетом выбора сделанного User-ом, необходимо
включить в query все связанные таблицы, примерно так :
Код: plaintext
1.
2.
3.
4.
5.
SELECT DISTINCT A.Country
FROM  A INNER JOIN
               R_A ON A.AID = R_A.AID INNER JOIN
               R ON R_A.RID = R.RID
WHERE (A.Country IN ('A', 'B')) AND (R.Journal IN ('1', '2', '3'))

и так для каждого списка меняя только выходное поле.

Теперь - real life :
таких связанных списков на клиенте больше 10-ти и они являются частью структуры
более чем 30 связанных таблиц.
Следовательно для обновления содержимого любого списка я каждый раз должен
связывать эту огромную структуру таблиц,
причем тело запроса абсолютно одинаковое для каждого списка, различается только выходное поле.
В результате получаю ужасно медленный вывод содержимого связанных списков.
Ну и собственно вопрос : что делать и кто виноват ?

Regards, Snark
...
Рейтинг: 0 / 0
Связанные списки
    #32065882
Фотография Gobzo Kobler
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сначала надо решить вопрос, что ты вообще делаешь. Связанные списки - точно не лучшее решение для SQL, который изначально не приспособлен оперировать понятиями "предыдущий" и "последующий".
...
Рейтинг: 0 / 0
Связанные списки
    #32065911
Snark
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Понятия "предыдущий" и "последующий" в этой задаче не присутствуют списки связаны
не "вертикально" а "горизонтально" ... может быть точнее будет сказать
не связанные а _синхронизированные_ списки ..
то есть такие, где содержимое одного списка зависит от содержимого другого списка.
По условиям задачи необходимо обновлять и синхронизировать содержимое каждого
списка с учетом критериев поиска введенных пользователем.
Например, в этом запросе, требуется вывести список уникальных названий журналов,
из таблицы R,
пользователя интересуют журналы с заголовками '1','2','3'
причем Авторы ( [dbo].[A] ) Публикаций ( [dbo].[R] ) в этих журналах должы быть из стран 'A','B', 'C'
Код: plaintext
1.
2.
3.
4.
5.
SELECT DISTINCT dbo.R.Journal
FROM  dbo.A INNER JOIN
               dbo.R_A ON dbo.A.AID = dbo.R_A.AID INNER JOIN
               dbo.R ON dbo.R_A.RID = dbo.R.RID
WHERE (dbo.A.Country IN ('A', 'B', 'C') AND dbo.R.Journal IN ('1', '2', '3'))               


получаем такой результат

Journal
--------------------------------------------------
1
2
3

если же запрошены журналы с заголовками '1','2','3' причем Авторы ( [dbo].[A] ) Публикаций ( [dbo].[R] )
в этих журналах должы быть из стран 'A','B'
Код: plaintext
1.
2.
3.
4.
5.
SELECT DISTINCT dbo.R.Journal
FROM  dbo.A INNER JOIN
               dbo.R_A ON dbo.A.AID = dbo.R_A.AID INNER JOIN
               dbo.R ON dbo.R_A.RID = dbo.R.RID
WHERE (dbo.A.Country IN ('A', 'B')) AND (dbo.R.Journal IN ('1', '2', '3'))

то получаем такой результат

Journal
--------------------------------------------------
1
2

то есть условия выборки из списка A.Country повлияли на содержимое списка R.Journal
так же точно определенные условия выборки из списка R.Journal
могут повлиять на содержимое списка A.Country
Критерии поиска, заданные для каждого списка, взаимно влияют на
обновленное содержание друг друга.

Для того чтобы вывести обновленное содержимое каждого списка,
каждый раз необходимо выполнять очень сложный запрос включающий несколько десятков INNER JOIN,
так как в реальной базе данных, описанные списки являются частью структуры
более чем 30 связанных таблиц

Например этот запрос, который выводит список стран основываясь на тех же критериях выборки,
что и предыдущий,
Код: plaintext
1.
2.
3.
4.
5.
SELECT DISTINCT dbo.A.Country
FROM  dbo.A INNER JOIN
               dbo.R_A ON dbo.A.AID = dbo.R_A.AID INNER JOIN
               dbo.R ON dbo.R_A.RID = dbo.R.RID
WHERE (dbo.A.Country IN ('A', 'B')) AND (dbo.R.Journal IN ('1', '2', '3'))

почти идентичен предыдущему запросу за исключением поля вывода : SELECT DISTINCT dbo.A.Country
Причем тело запроса - очень большое
(так как в реальной задаче тело запроса состоит из нескольких десятков INNER JOIN)
и отнимает львиную долю времени выполнения запроса.
Напрашивается вопрос - нельзя ли как то reuse тело запроса,
так чтобы запускать етот большой и сложный запрос один раз а потом использовать его
результаты для быстрого обновления содержимого списков.
Какие еще могут быть решения в этой ситуации ?

Regards, Snark
...
Рейтинг: 0 / 0
Связанные списки
    #32065946
Фотография MiCe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
может я чего то не допонял?
View не пойдет?
Код: plaintext
1.
2.
3.
4.
5.
6.
CREATE VIEW vw_r_a
AS
SELECT A.AID, A.[Name] ,A.[Country],
           R.RID, R.[Title], R.[Journal] 
FROM  A INNER JOIN
               R_A ON A.AID = R_A.AID INNER JOIN
               R ON R_A.RID = R.RID
...
Рейтинг: 0 / 0
Связанные списки
    #32065959
Snark
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Используешь ты View или нет тело запроса не меняется и
соответственно не меняется время выполнения запроса.
я как раз пытаюсь найти способ уменьшения времени выполнения запроса.
Кстати я действительно в реальной задаче использую View но
серверу все равно приходится JOIN эту кучу таблиц чтобы
вывести список из 100 записей для каждого из 10 списков .. неэффективно.
Вопрос собственно в масштабируемости данного подхода, когда требуется
JOIN 2-5 таблиц для вывода одного списка это довольно эффективный запрос,
когда же число таблиц больше 30 и приходится повторять почти идентичый запрос
для вывода 10-20 списков это становится абсолютно неефективным, медленным подходом,
да и выглядит как то не "нормально".
Одним из подходов который я "изобрел" было сбрасывать содержимое View
во временную таблицу, в рассчете на то что многочисленные JOIN будут
производится только один раз а потом выборка значений списков будет происходить
с помощью относительно быстрого запроса
Код: plaintext
1.
2.
3.
4.
  
SELECT DISTINCT Country FROM #MyTable
SELECT DISTINCT Journal FROM #MyTable
etc.

работает неплохо для JOIN 5-10 - таблиц, но когда число таблиц увеличивается -
размер временной таблицы растет в геометрической прогрессии,
и время на создание этой таблицы становится просто неприемлемым,
да и размер этой временной таблицы начинает измерятся гигабайтами.
Другой подход очевиден - разбить многочисленные JOINs,
на части которые логически не зависят друг от друга - количество JOIN
уменьшится для создания каждого отдельного списка,
так же как и время выполнения запроса.
Ответ - независимых списков нет, выбор в каждом списке может повлиять на
содержимое любого другого.
Как то не верится что нет нормального решения этой ситуации,
не я же один использую синхронизированные списки.

Regards, Snark
...
Рейтинг: 0 / 0
Связанные списки
    #32065961
Фотография MiCe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
если серв 2к сторой индексированное представление....
...
Рейтинг: 0 / 0
Связанные списки
    #32065980
Snark
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Indexed views не позволяют использование LEFT OUTER JOIN которые присутствуют в реальном запросе
...
Рейтинг: 0 / 0
Связанные списки
    #32065999
dao
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а ты попробуй условие выборки запихнуть в join а не в where - по логики должно на много сократить время выборки
...
Рейтинг: 0 / 0
Связанные списки
    #32066225
Snark
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нельзя ли привести примерчик как в моем случае условие выборки запихнуть в join ? Все условия выборки в моем случае это where .. in(1,2,3..n)
Regards, Snark
...
Рейтинг: 0 / 0
Связанные списки
    #32066233
Фотография MiCe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
строй индексированные вью без outer...
а запрос можно переделать..... все равно быстрее будет....
...
Рейтинг: 0 / 0
Связанные списки
    #32066248
Snark
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
To MiCe :
Пробовал, создал индексированное представление - ViewIN, содержащее только INNER JOIN и
включил его в другое представление - ViewOUT, где содержатся LEFT OUTER JOIN.
Также для запроса ViewIN, кроме кластерного индекса, создал индексы для всеx полей
по которым может происходить JOIN а также для всех полей по которым может идти поиск.
Запрос для заполнение списка журналов, с использованием индексированного представления :
Код: plaintext
1.
2.
   Select DISTINCT Journal from ViewOUT where 
    WHERE (Country IN ('A', 'B')) AND (Journal IN ('1', '2', '3'))
  

работает на 8% быстрее чем такой же запрос с использованием неиндексированного представления.
Причем под индексы для индексированного представления ViewIN зарезервированно 1408 KB,
тогда как неиндексированное представление, как известно, места не занимает.
Также проверял производительность непосредственно для индексированной и неиндексированной
версии представления ViewIN - разницы вообще нет, или она статистически недостоверна, колеблется
на доли процента в обе стороны.
Игра не стоит свеч.

Regards, Snark
...
Рейтинг: 0 / 0
Связанные списки
    #32066301
Фотография MiCe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ViewOUT не нужно....
строй идксы которых нет в исходных таблицах...
OUTER join можно вообще не использовать...
игра вообще нестоит свеч если операций вставки столькоже сколько и чтений.....
по оптимизации... избегай по возможности IN...
меняй на EXISTS... ограничивай наборы до объединения...
...
Рейтинг: 0 / 0
Связанные списки
    #32066326
dao
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Согласен с MiCe замени in на exist ы или несколько = ; А вот пример с join
Код: plaintext
1.
2.
3.
4.
5.
FROM  A INNER JOIN

               R_A ON A.AID = R_A.AID  and (A.Country= 'A' or  A.Country='B') INNER JOIN

               R ON R_A.RID = R.RID AND (R.Journal  like ([ 1 - 3 ])

Like привел для примера - на самом деле тоже медленно работает, лучьше используй =
...
Рейтинг: 0 / 0
Связанные списки
    #32066353
Snark
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ViewOUT не нужно....
- понимаю что ViewOUT не обязателен, но на производительность не влияет
строй идксы которых нет в исходных таблицах...
- это хорошее замечание помогло сократить размер ViewIN в несколько раз, спасибо
OUTER join можно вообще не использовать...
- тут я не понял, как без OUTER JOIN ? ..
например зачем LEFT OUTER JOIN используется в моей задаче :
кроме описанных выше таблиц, есть таблица Reference_User
Код: plaintext
1.
CREATE TABLE [dbo].[Reference_User]([ReferenceID] [int] NOT NULL, [UserID] [int] NOT NULL) ON [PRIMARY]

дело в том что некоторые Публикации - конфиденциальны и могут показываться только определенным Пользователям,
поэтому создана такая таблица где хранится информация о таких комбинациях :
Конфиденциальной публикации и Пользователя который ее может видеть
поэтому запрос для заполнения списка журналов на самом деле выглядит так :
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
SELECT DISTINCT dbo.R.Journal
FROM         dbo.A INNER JOIN
                      dbo.R_A ON dbo.A.AID = dbo.R_A.AID INNER JOIN
                      dbo.R ON dbo.R_A.RID = dbo.R.RID LEFT OUTER JOIN
                      dbo.Reference_User ON dbo.R.RID = dbo.Reference_User.ReferenceID
WHERE     (dbo.A.Country IN ('A', 'B')) AND (dbo.R.Journal IN ('1', '2', '3')) AND 
          (dbo.Reference_User.ReferenceID =  133  OR dbo.Reference_User.ReferenceID IS NULL))) 

будут показаны журналы только с названиями "1", "2" или "3" где авторы публикаций в этих
журналах из стран "А" или "B", причем будут показаны только конфиденциальные публикации
разрешенные для просмотра Пользователю 123 И все публикации которые находятся в свободном
доступе. Как в данном случае обойтись без LEFT OUTER JOIN ?

игра вообще нестоит свеч если операций вставки столькоже сколько и чтений.....
- В данной задаче операции чтения гораздо чаще чем операции INSERT и UPDATE,
хотя интересно не может ли блокировать созданный кластерный индекс ViewIN операции INSERT и UPDATE ?
по оптимизации...
избегай по возможности IN... меняй на EXISTS...

опять не понимаю как в данном случае можно заменить IN на EXISTS ?
Все критерии выборки приходят с клиента, пользователь может выбирать произвольные
значения из любого синxронизированного списка, предсказать какие значения прийдут с
клиента невозможно.
ограничивай наборы до объединения...
это я понимаю, и имею в виду, но не вижу возможностей ограничения

кстати, включение опции WITH (NOEXPAND) действительно заставило индексированное
представление ViewIN работать значительно (примерно в 10 раз) быстрее,
но после наложения всех критериев выборки, план выполнения запроса опять сбивается
и в итоге скорость выполнения запроса с использованием индексированного представления
становится такой же как и с использованием такого же неиндексированного представления

Regards, Snark
...
Рейтинг: 0 / 0
Связанные списки
    #32066373
Фотография MiCe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
в данном случае поможет OR....
(dbo.A.Country IN ('A', 'B')) ->(dbo.A.Country = 'A' OR dbo.A.Country = 'B')....(посмотри план... может вынести вообще в from / FROM dbo.A ->FROM (select * from dbo.A where dbo.A.Country = 'A' OR dbo.A.Country = 'B') as a / )

кароче.... ;)) вот....
Код: plaintext
1.
2.
3.
4.
5.
6.
SELECT DISTINCT dbo.R.Journal
FROM  (select AID from dbo.A where Country='A' OR Country='B') a INNER JOIN
                      dbo.R_A ra ON a.AID = ra.AID INNER JOIN
      (select RID,Journal from dbo.R where Journal='1' OR Journal='2' OR Journal='3') r ON ra.RID = r.RID 
WHERE  r.RID= 133  OR 
NOT EXISTS (SELCT top  1  * from dbo.Reference_User ru where ru.ReferenceID=r.RID ) 
...
Рейтинг: 0 / 0
Связанные списки
    #32066379
Фотография MiCe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
скорость думаю на порядок вырастет... ;))
...
Рейтинг: 0 / 0
Связанные списки
    #32066386
Snark
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
виноват...
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
 
 SELECT DISTINCT dbo.R.Journal
FROM         dbo.A INNER JOIN
                      dbo.R_A ON dbo.A.AID = dbo.R_A.AID INNER JOIN
                      dbo.R ON dbo.R_A.RID = dbo.R.RID LEFT OUTER JOIN
                      dbo.Reference_User ON dbo.R.RID = dbo.Reference_User.ReferenceID
WHERE (dbo.A.Country IN ('A', 'B')) AND (dbo.R.Journal IN ('1', '2', '3')) AND     
(dbo.Reference_User.UserID =  133 ) OR (dbo.Reference_User.UserID IS NULL)

ne
dbo.Reference_User.ReferenceID = 133
a
dbo.Reference_User.UserID =133

Snark
...
Рейтинг: 0 / 0
Связанные списки
    #32066393
Snark
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
если делать так как вы с дао предложили:
Код: plaintext
1.
2.
SELECT DISTINCT dbo.R.Journal
FROM  (select AID from dbo.A where Country='A' OR Country='B') a INNER JOIN

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

- я честно говоря не понимаю смысла этой замены,
(dbo.A.Country IN ('A', 'B')) ->(dbo.A.Country = 'A' OR dbo.A.Country = 'B')....
тем более что сервер, судя по плану выполнения запроса, сам делает это преобразование,
а я изпользую WHERE IN просто потому что ето более компактный способ передачи критерия
выборки на сервер
...
Рейтинг: 0 / 0
Связанные списки
    #32066553
dao
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А смысл в том что where -накладывается после обьединения а предложенные нами варианты до.Следовательно в обьединение участвует намного меньше записей.
...
Рейтинг: 0 / 0
Связанные списки
    #32066635
Фотография MiCe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
строим индексированные представления для двух целей...
получить дополнительные индексы при сложном объединении и получать просчитанные результаты....
ограничиваем выборки до объединения....
в остальном сервер сам разбирется... и индексы будет использовать и результаты...
оптимизатор у мелкомягких один из самых лучших... но он тоже не гений... ;))) если ему помогать - хорошая спака получается....
...
Рейтинг: 0 / 0
Связанные списки
    #32067175
Snark
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо за очень интересное обсуждение
Regards, Snark
...
Рейтинг: 0 / 0
21 сообщений из 21, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Связанные списки
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]