Что может ускорить запрос подсчета SQL?

9

При выполнении подсчета (агрегатного) SQL-запроса, что может ускорить время выполнения в этих 3 системах баз данных? Я уверен, что многие вещи могут ускорить его (аппаратное обеспечение для одного), но я просто начинающий администратор баз данных, поэтому я уверен, что здесь я получу несколько ответов. Я перенес около 157 миллионов строк в базу данных SQL Server, и этот запрос занимает вечность. Но в моей исходной базе данных Netezza это занимает секунды.

Например:

Нетезза 6:

SELECT COUNT(*) FROM DATABASENAME..MYTABLE

Oracle 11g:

SELECT COUNT(*) FROM MYTABLE

SQL Server 2012:

SELECT COUNT(*) FROM DATABASENAME.[dbo].[MYTABLE]
МакГайвер
источник
Можно посмотреть на этот вопрос: stackoverflow.com/questions/11130448/sql-count-performance
1
Вам нужно сделать это только один раз или несколько раз?
Джон Зигель
@JonSeigel мы выполняем инкрементную загрузку, и каждый день мы сравниваем записи между системами баз данных, чтобы убедиться в том, что они суммируются. Так неоднократно.
MacGyver

Ответы:

10

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

Для вашего SQL Server вы можете значительно ускорить подсчет строк, выполнив запрос из DMV sys.dm_db_partition_stats.

SELECT s.name AS [Schema], o.name AS [Table], SUM(p.row_count) AS [RowCount]
FROM sys.dm_db_partition_stats p JOIN sys.objects o
ON p.object_id = o.object_id JOIN sys.schemas s
ON o.schema_id = s.schema_id
WHERE p.index_id < 2
AND o.object_id = object_id('MyTable')
GROUP BY o.name, s.name;

В условиях высокой транзакции этот DMV не гарантирует 100% точности. Но, исходя из вашего вопроса, кажется, что вы просто делаете подсчет строк, чтобы проверить каждую таблицу после переноса, поэтому этот запрос должен работать для вас.

Патрик Кейслер
источник
4
@ Почему? Если вы просматриваете таблицы и выполняете дорогостоящий SELECT COUNT (*) для каждой из них - насколько точным будет первый результат после достижения последней таблицы?
Аарон Бертран
1
Для ясности Фил сказал: «Использование словаря данных, который не дает 100% точных результатов, - плохой совет. По моему мнению, ответ должен быть либо отредактирован, чтобы удалить предложение, либо удален - запомните людей, гугл за такие ответы, и будете слепо». вырезать и вставлять ... "Я согласен с тем, что отказ от ответственности важен (и есть предположительно некоторые крайние случаи, когда метаданные не дают ощутимых результатов), я не согласен с тем, что использование представлений метаданных в целом - плохой совет.
Аарон Бертран
5

Вот решение SQL Server, которое использует COUNT_BIGвнутри индексированного представления. Это даст вам согласованный с точки зрения транзакций счет без затрат на сканирование больших таблиц или индексов и без необходимости хранения, необходимого для последнего:

CREATE TABLE [dbo].[MyTable](id int);
GO

CREATE VIEW [dbo].[MyTableRowCount]
    WITH SCHEMABINDING
AS

    SELECT
        COUNT_BIG(*) AS TableRowCount
        FROM [dbo].[MyTable];
GO

CREATE UNIQUE CLUSTERED INDEX IX_MyTableRowCount
    ON [dbo].[MyTableRowCount](TableRowCount);
GO

SELECT
    TableRowCount
    FROM [dbo].[MyTableRowCount] WITH(NOEXPAND);

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

Джон Сайгель
источник
@SQLKiwi: Почему чтения заблокированы до 2012 года? Ошибка SQL Server?
Джон Зигель
@JonSeigel - Мои $ 0,05: обычные кластеризованные индексы для обычной таблицы, созданные в автономном режиме, применяют блокировку Sch-M к таблице. В представлении, конечно, это не нужно, но это означает изменение операции Create Index для создания особого случая для индексированного представления - что было сделано для SQL2012. ИМХО, конечно.
Фабрицио Араужо
3

В Oracle двоичный индекс дерева в столбце NOT NULL может использоваться для ответа на COUNT (*). В большинстве случаев это будет быстрее, чем FULL TABLE SCAN, поскольку индексы обычно меньше их базовой таблицы.

Тем не менее, обычный индекс двоичного дерева будет по-прежнему огромным с 157 Mrows. Если ваша таблица не обновляется одновременно (т. Е. Только процесс пакетной загрузки), то вы можете использовать вместо этого индекс растрового изображения.

Наименьший индекс растрового изображения будет выглядеть примерно так:

CREATE BITMAP INDEX ix ON your_table(NULL);

Пустые записи учитываются с помощью растрового индекса. Полученный индекс будет крошечным (20–30 блоков на миллион строк) по сравнению с обычным двоичным индексом дерева или базовой таблицей.

Полученный план должен показать следующие операции:

----------------------------------------------
| Id  | Operation                     | Name | 
----------------------------------------------
|   0 | SELECT STATEMENT              |      |
|   1 |  SORT AGGREGATE               |      |
|   2 |   BITMAP CONVERSION COUNT     |      |
|   3 |    BITMAP INDEX FAST FULL SCAN| IX   |
----------------------------------------------

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

Винсент Малграт
источник
3

В Oracle простой запрос подсчета часто выполняется путем сканирования индекса вместо всей таблицы. Индекс должен быть битовым индексом или определяться для столбца с ограничением NOT NULL. Для более сложных запросов, требующих полного сканирования таблицы, вы можете использовать параллельный запрос.

Чтобы включить параллельный запрос (требуется Enterprise Edition), вы можете использовать подсказку оптимизатора:

select /*+ PARALLEL(mytable, 12) */ count(*) from mytable;

Или включите параллельный запрос для всех запросов в таблице:

alter table mytable parallel 12;
СЖК
источник