Оптимизировать запрос на обновление - PullRequest
3 голосов
/ 05 января 2012

Я ищу предложения по оптимизации этого запроса, который уже выполняется более часа и содержит около 300 000 строк в таблице.Мы используем инструмент отчетности, который требует, чтобы данные были в такой форме, когда они извлекаются, поэтому перепроектирование структуры таблицы не вариант.Таблица выглядит следующим образом:

CREATE TABLE [datatable](
    [RowID] [int] IDENTITY(1,1) NOT NULL,
    [CampaignID] [int] NOT NULL,
    [CampaignName] [nvarchar](255) NULL,
    [Category] [nvarchar](255) NOT NULL,
    [PostID] [int] NOT NULL,
    [TopicName] [nvarchar](4000) NULL,
    [TopicFrequency] [int] NULL
)

Данные постоянно добавляются в таблицу, поэтому мне приходится периодически обновлять частоты тем.Вот мой текущий запрос:

UPDATE  datatable
SET     TopicFrequency = b.TopicFrequency
FROM    datatable INNER JOIN
  (SELECT CampaignID, Category, TopicName, COUNT(DISTINCT PostID) AS TopicFrequency
    FROM datatable GROUP BY CampaignID, Category, TopicName) AS b 
    ON datatable.CampaignID = b.CampaignID 
    AND datatable.Category = b.Category 
    AND datatable.TopicName = b.TopicName

С именем темы nvarchar 4000 я не могу создать индекс на поле.Ищу идеи.Спасибо.

Ответы [ 4 ]

1 голос
/ 05 января 2012

Общее решение - это разбить вашу таблицу на две или более таблиц, т.е. нормализовать структуру данных. Я думаю, что можно ввести еще две таблицы - для кампаний и тем

НО

Для ваших существующих структур данных вы можете создать вычисляемый столбец uniqueidentifier или bigint в виде хеша поля TopicName, проиндексировать его и искать хеш вместо строкового поля. Я приведу вам пример с bigint:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[HashString64SVF](@input NVARCHAR(4000))
RETURNS BIGINT
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT 
AS 
BEGIN
    RETURN
        CAST(SUBSTRING(HASHBYTES('SHA1', UPPER(@Input)), 1, 8) AS BIGINT) 
    ^   CAST(SUBSTRING(HASHBYTES('SHA1', UPPER(@Input)), 9, 8) AS BIGINT) 
    ^   CAST(SUBSTRING(HASHBYTES('SHA1', UPPER(@Input)), 17, 4) AS BIGINT) 
END
GO
ALTER TABLE datatable ADD TopicNameHash AS dbo.HashString64SVF(TopicName)
GO
CREATE INDEX NewIndexName ON DataTable(TopicNameHash, CampaignID, Category) INCLUDE(PostId)
GO
UPDATE  datatable
SET     TopicFrequency = b.TopicFrequency
FROM    datatable 
JOIN
  (SELECT CampaignID, Category, TopicNameHash, COUNT(DISTINCT PostID) AS TopicFrequency
    FROM datatable GROUP BY CampaignID, Category, TopicNameHash) AS b 
    ON datatable.CampaignID = b.CampaignID 
    AND datatable.Category = b.Category 
    AND datatable.TopicNameHash = b.TopicNameHash

И

Создание первичного ключа в столбце RowId

И

Воссоздайте таблицу следующим образом:

CREATE TABLE [datatable](
    [RowID] [int] IDENTITY(1,1) PRIMARY KEY,
    [CampaignID] [int] NOT NULL,
    [Category] [nvarchar](255) NOT NULL,
    [PostID] [int] NOT NULL,
    --uncomment if needed [TopicNameHash] AS dbo.HashString64SVF(TopicName),
    [TopicFrequency] [int] NULL,
    [CampaignName] [nvarchar](255) NULL,
    [TopicName] [nvarchar](4000) NULL
)

Основная причина - если столбцы переменных с пустыми значениями находятся в конце списка столбцов и в этих столбцах много значений NULL - сервер sql может сэкономить немного места в строке и, следовательно, - в IO

0 голосов
/ 05 января 2012

У меня была похожая проблема некоторое время назад: стороннее программное обеспечение использовало таблицу, которая была слишком большой для какой-либо манипуляции с данными.Уловка, которую я сделал, чтобы решить проблему, заключалась в следующем:

  1. создать оптимизированную структуру таблицы и скопировать данные из старой таблицы
  2. Удалить старую таблицу
  3. Создать представление с тем же именемкак удаленная таблица, которая использует оптимизированную структуру и имеет ту же структуру, что и старая таблица

Для стороннего программного обеспечения не было никакой разницы между таблицей и представлением.

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

0 голосов
/ 05 января 2012

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

0 голосов
/ 05 января 2012

Триггер

Обновить поле частоты при вставке / обновлении / удалении данных?Спреды загружаются с течением времени, и обновляются только те записи, которые относятся к измененным данным.

TopicID

Иметь таблицу тем, которая может иметь или не иметь больше, чем просто id, name.После этого вы можете использовать (и индексировать) TopicID.

Поскольку у вас есть TopicName в GROUP BY и JOIN, возможность индексировать это приведет к существенной разнице в производительности .

LastModified или другое отслеживание аудита

Запись (и включение в индекс) времени последнего изменения или другое отслеживание аудита.Это позволит вам ограничить область обновления только темами, в которые были вставлены / обновлены / удалены записи с момента последнего пакетного процесса.

Нормализация

Сохраните значение частоты в другой таблице с ключом Campaign, Category, Topic.

В настоящее время, если ваш COUNT (*) дает 100, выобновление 100 записей.Нормализация означает одно обновление для каждой группы.

Очевидное примечание?

Только из-за того, что вы нормализуете или реорганизуете базовые данные, вам (не так ли?) Не мешают заменить эту таблицу видом на «лучше» спроектированную структуру?

Средство создания отчетов читает представление, как если бы оно было таблицей.Обработка данных напрямую взаимодействует с реорганизованной структурой таблиц более эффективным способом .

Разделение принципов представления данных и обработки данных сделает вас гораздо более свободным человеком.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...