2016-06-30 3 views
0

У меня есть набор таблицSQL Server 2014 Оптимизация таблиц/Query

dbo.Store_000 
dbo.Store_001 
.... 
dbo.Store_216 

, содержащий продажи различных магазинов, где соответствующие поля являются

Username, ItemID, Description, CreatedDate, CountryID 

Мне нужно извлечь последние 20 продаж от all Stores and I написал следующий запрос:

select top 20 UserName, ItemID, Description, CreatedDate, CountryID 
FROM ( 
    SELECT UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_000 
    UNION ALL 
    SELECT UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_001 
    UNION ALL 
    SELECT UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_002 
    ..... 
    ... 
    UNION ALL 
    SELECT UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_216     
) ii 
order by ii.createdDate desc 

В настоящее время таблицы содержат около 200 млн записей (все вместе г)

поэтому сократить время обработки я создал следующий индекс для каждой таблицы:

CREATE NONCLUSTERED INDEX I2_Store000 ON dbo.Store_000 
    (UserName) 
INCLUDE (itemId, Description, CreatedDate, CountryID) 
WITH (
    PAD_INDEX = OFF, 
    DROP_EXISTING = OFF, 
    STATISTICS_NORECOMPUTE = OFF, 
    SORT_IN_TEMPDB = OFF, 
    ONLINE = OFF, 
    ALLOW_ROW_LOCKS = ON, 
    ALLOW_PAGE_LOCKS = ON) 
ON [PRIMARY] 

, но она по-прежнему занимает слишком много (несколько минут на нашей машине)

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

Следует ли создать индекс на основе CreateDate, так как это поле сортировки?

если это может помочь, HERE может найти план выполнения MSSMS.

благодарит

+0

Eralper правильно. Кроме того, вы игнорируете Теорию набора данных, рассматривая записи как курсоры и, по существу, выполняете 21 различный запрос. Интернет полна продуктивных руководств по созданию запросов, таких как thinkbot.com, blog.SQLAuthority и TECHNET. Чтобы быстро обновить запрос, ознакомьтесь с [страницей Thoughtbot] (https://robots.thoughtbot.com/back-to-basics-sql) –

+0

Привет, что вы имеете в виду для 'Data Set Theory, рассматривая записи как курсоры и в основном работает 21 разные запросы'? где я могу найти что-то об этом. – Joe

+0

Одним из способов сказать, что языки баз данных не являются такими, как C++, и обрабатывать таблицы (наборы данных) в целом. Проверьте SQLMag [T-SQL Foundations: Thinking in Sets] (http://sqlmag.com/t-sql/t-sql-foundations-thinking-sets) –

ответ

2

Только для исполнения, я должен выбрать только верхние 20 строк из каждой таблицы по заказу createdDate, а затем выбрать новый топ-20 из новой производной таблицы, которая составляет около 17 таблиц * 20 = 340 строк

Надеюсь, что с меньшим столом будет легче справиться, я действительно удивляюсь результату.

+0

Привет, спасибо за быстрый ответ .. на самом деле ситуация улучшилась, но не достаточно: теперь требуется около 4 минут, но удаление внутренней сортировки занимает около 1 секунды, поэтому я думаю, что мне нужно создать индекс на основе createdDate, чтобы избежать сортировки, но поскольку у меня есть другой индекс, я должен понять, лучше ли (и возможно) расширить этот индекс или создать второй индекс. – Joe

+0

@Joe. Для чего этот индекс? Единственный «предикат», который у вас есть, сортируется по 'createdDate' и' TOP'. Как может быть полезен индекс в 'UserName'? –

+0

Хорошо, что на самом деле это индекс, который у меня уже есть на этой таблице, так как мне нужно присоединиться к этой таблице с другим именем пользователя, и я добавляю 'CreatedDate' в include, но не очень помогает, с другой стороны я бы хотел создать дополнительный индекс для некоторых записей 200M – Joe

0

Первый (и более быстрый) вариант будет выполнять TOP 20 на ваших подзапросах, прежде чем вы затем сортируете внешний выбор, что-то вроде этого;

select top 20 UserName, ItemID, Description, CreatedDate, CountryID 
FROM ( 
    SELECT TOP 20 UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_000 ORDER BY CreatedDate DESC 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_001 ORDER BY CreatedDate DESC 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_002ORDER BY CreatedDate DESC 
    ..... 
    ... 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_216 ORDER BY CreatedDate DESC     
) ii 
order by ii.createdDate desc 

Индекс, который вы захотите на каждой таблице, будет таким, как это (имя индекса просто пример);

CREATE NONCLUSTERED INDEX [IX_Store_000_CreatedDate_Desc_Incl] ON [dbo].[Store_000] ([CreatedDate] DESC) 
INCLUDE ([UserName],[ItemID],[Description],[CreatedDate],[CountryID]) 

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

https://www.simple-talk.com/sql/learn-sql-server/sql-server-indexed-views-the-basics/

https://www.brentozar.com/archive/2013/11/what-you-can-and-cant-do-with-indexed-views/

SQL Server - Creating an Indexed View

0

Есть другие методы, которые вы можете использовать, которые могли бы оптимизировать запрос. Теперь UNION ALL подходит, поскольку значения из каждой таблицы должны быть уникальными.

Алекс Мартелл из What is the difference between JOIN and UNION?

UNION помещает строку из запросов друг за другом, в то время как РЕГИСТРИРУЙТЕСЬ делает декартово произведение и подмножества его - совершенно другие операции.Trivial пример UNION:

mysql> SELECT 23 AS bah 
    -> UNION 
    -> SELECT 45 AS bah; 
+-----+ 
| bah | 
+-----+ 
| 23 | 
| 45 | 
+-----+ 2 rows in set (0.00 sec) similary trivial example of JOIN: 

mysql> SELECT * FROM 
    -> (SELECT 23 AS bah) AS foo 
    -> JOIN 
    -> (SELECT 45 AS bah) AS bar 
    -> ON (33=33); 
+-----+-----+ 
| bah | bah | 
+-----+-----+ 
| 23 | 45 | 
+-----+-----+ 1 row in set (0.01 sec) 
  • ИСПОЛЬЗУЙТЕ PREDICATE ВО ВСЕХ 20+ таблицах.

UNION ALL может быть эффективным, но он все еще должен сортировать всю таблицу, чтобы определить TOP 20. Вместо этого при условии, что магазины всегда имеют более 20 продаж в указанный период 30 дней, используйте DATEADD или DATEDIFF для включения boolean сравнения, которые ограничивают количество строк SQL Server, должны быть возвращены перед сравнением.

  • использовать индексную ... в правой колонке

Очевидно, что отчет должен использовать INDEXES и логических при этом. CLUSTERED INDEXES дешевле строить и обслуживать.

Вы знаете, что имена могут быть уникальными, но SQL Server не сравнивает имена ... он сравнивает DATES. Поэтому создайте INDEX на createdDate.

  • USE Поиск аргументация (SARGS)

Даже лучшие планы могут быть разрушенными, если SQL Server думает, что это должно пройти через каждую запись каждый раз. Когда FUNCTION или переменной используются по обе стороны предиката, как показано ниже:

createdDATE BETWEEN DATEADD(DD, createdDate, 30) AND CAST(GETDATE() AS DATETIME2)

SQL Server не имеет никакого выбора, кроме как пройти через всю таблицу или индекс списка (TABLE/INDEX SCAN) до сравнения значений. Вместо этого, изменить порядок так:

createdDATE >= DATEADD(DD, -30, GETDATE())

Сравните результаты с этим запросом и как индекс на createdDate улучшает время:

SELECT UserName, ItemID, Description, CreatedDate, CountryID 
FROM ( 
    SELECT TOP 20 UserName, ItemID, [Description], CreatedDate, CountryID FROM dbo.Store_000 
    WHERE CreatedDate >= DATEADD(DD, -30, GETDATE()) 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, [Description], CreatedDate, CountryID FROM dbo.Store_001 
    WHERE CreatedDate >= DATEADD(DD, -30, GETDATE()) 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, [Description], CreatedDate, CountryID FROM dbo.Store_002 
    WHERE CreatedDate >= DATEADD(DD, -30, GETDATE()) 
    ..... 
    ... 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, [Description], CreatedDate, CountryID FROM dbo.Store_216 
    WHERE CreatedDate >= DATEADD(DD, -30, GETDATE()) 
) ii 
-- ORDER BY CreatedDate DESC /*Unless you must, drop the ORDER BY. */ 
+0

Все это пример использования реляционных данных. :) –

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