Я сталкивался со статьями, в которых говорится, что SELECT COUNT(*) FROM TABLE_NAME
будет медленно, когда в таблице много строк и много столбцов.
У меня есть таблица, которая может содержать даже миллиарды строк (в ней примерно 15 столбцов). Есть ли лучший способ получить точный счетчик количества строк в таблице?
Пожалуйста, рассмотрите следующее перед вашим ответом:
Я ищу независимое решение от поставщика базы данных. Это нормально, если он охватывает MySQL , Oracle , MS SQL Server . Но если на самом деле не существует независимого от поставщика баз данных решения, я остановлюсь на разных решениях для разных поставщиков баз данных.
Я не могу использовать любой другой внешний инструмент для этого. Я в основном ищу решение на основе SQL.
Я не могу больше нормализовать дизайн моей базы данных. Он уже в 3NF, и, кроме того, много кода уже написано вокруг него.
Ответы:
Простой ответ:
COUNT(*)
Ноты:
COUNT (1) = COUNT (*) = COUNT (PrimaryKey) на всякий случай
Редактировать:
Пример SQL Server (1,4 миллиарда строк, 12 столбцов)
1 пробег, 5:46 минут, счет = 1 401 659 700
2 прогона, оба менее 1 секунды, количество = 1 401 659 670
Второй имеет меньше строк = неправильно. Будет одинаковым или более в зависимости от записи (удаление выполняется в нерабочее время)
источник
COUNT(*) = COUNT(key)
. Это просто неправильно. Если нетNOT NULL
ограничений - тогда они могут быть не равны (как в результатах, так и в плане выполнения).index_id < 2
?Самый быстрый способ на MySQL - это:
Вы сразу получите все свои таблицы с количеством строк (которое является общим) вместе с большим количеством дополнительной информации, если хотите.
источник
Это зависит от базы данных. Некоторые ускоряют подсчет, например, отслеживая, являются ли строки живыми или мертвыми в индексе, что позволяет сканировать только индекс, чтобы извлечь количество строк. Другие этого не делают, и, следовательно, требуют посещения всей таблицы и подсчета живых строк по одной. Либо будет медленно для огромного стола.
Обратите внимание, что в целом вы можете извлечь хорошую оценку, используя инструменты оптимизации запросов, статистику таблиц и т. Д. Например, в случае с PostgreSQL вы можете проанализировать выходные данные
explain count(*) from yourtable
и получить достаточно хорошую оценку числа строк. Что подводит меня к вашему второму вопросу.Шутки в сторону? :-) Вы действительно имеете в виду точное количество таблиц с миллиардами строк? Вы действительно уверены? :-)
Если вы действительно это сделаете, вы можете отслеживать общий итог, используя триггеры, но помните о параллелизме и взаимоблокировках, если вы это делаете.
источник
Чтобы ответить на ваш вопрос просто, нет .
Если вам нужен независимый от СУБД способ сделать это, самый быстрый способ всегда будет:
У некоторых поставщиков СУБД могут быть более быстрые способы, которые будут работать только для их систем. Некоторые из этих вариантов уже опубликованы в других ответах.
COUNT(*)
в любом случае должна быть оптимизирована СУБД (по крайней мере, любой достойной БД PROD), поэтому не пытайтесь обойти их оптимизацию.С другой стороны:
я уверен, что выполнение многих других ваших запросов также занимает много времени из-за размера таблицы. Любые проблемы с производительностью, вероятно, следует решать, думая о дизайне схемы с учетом скорости. Я понимаю, что вы сказали, что это не вариант изменить, но может оказаться, что более 10 минутных запросов тоже не вариант. 3-я NF не всегда лучший подход, когда вам нужна скорость, и иногда данные могут быть разделены на несколько таблиц, если записи не должны храниться вместе. Что-то думать о...
источник
Я получил этот скрипт из другого вопроса / ответа StackOverflow:
В моей таблице 500 миллионов записей, а результат выше чем за 1 мс. В то же время,
занимает целых 39 минут 52 секунды!
Они дают одинаковое количество строк (в моем случае, точно 519326012).
Я не знаю, будет ли это всегда так.
источник
Вы можете попробовать это sp_spaceused (Transact-SQL)
источник
Если выпуск SQL Server 2005/2008, вы можете использовать DMV для вычисления количества строк в таблице:
Для ядра базы данных SQL Server 2000 будут работать sysindexes, но настоятельно рекомендуется избегать его использования в будущих выпусках SQL Server, поскольку он может быть удален в ближайшем будущем.
Пример кода взят из: Как быстро и безболезненно получить счетчик строк таблицы
источник
я использую
источник
Я не настолько эксперт, как другие, кто ответил, но у меня возникла проблема с процедурой, которую я использовал для выбора случайной строки из таблицы (не слишком релевантно), но мне нужно было знать количество строк в моей справочной таблице. рассчитать случайный индекс. Используя традиционную работу Count (*) или Count (1), но я иногда получал до 2 секунд для выполнения моего запроса. Поэтому вместо этого (для моей таблицы с именем 'tbl_HighOrder') я использую:
Он отлично работает и время запросов в Management Studio равно нулю.
источник
Ну, опоздал на 5 лет и не уверен, поможет ли это
Я пытался посчитать нет. строк в таблице SQL Server с использованием MS SQL Server Management Studio и столкнулся с некоторой ошибкой переполнения, тогда я использовал следующее:
выберите count_big (1) FROM [имя_БД]. [dbo]. [FactSampleValue];
Результат :
24296650578 строк
источник
Я нашел эту хорошую статью SQL Server - HOW-TO: быстро получить точное количество строк для таблицы из
martijnh1
которой можно получить хорошее резюме для каждого сценария.Мне нужно, чтобы это было расширено, где я должен предоставить счет, основанный на определенном условии, и когда я придумаю эту часть, я обновлю этот ответ дальше.
А пока вот подробности из статьи:
Способ 1:
Запрос:
Комментарии:
Выполняет полное сканирование таблицы. Медленно на больших столах.
Способ 2:
Запрос:
Комментарии:
Быстрый способ получить количество строк. Зависит от статистики и неточно.
Запустите DBCC UPDATEUSAGE (База данных) с COUNT_ROWS, что может занять значительное время для больших таблиц.
Способ 3:
Запрос:
Комментарии:
Способ, которым студия управления SQL подсчитывает строки (посмотрите на свойства таблицы, хранилище, количество строк). Очень быстро, но все же приблизительное количество строк.
Способ 4:
Запрос:
Комментарии:
Быстрая (хотя и не такая быстрая, как метод 2) операция и, что не менее важно, надежная.
источник
Я не думаю, что есть общее всегда быстрое решение: некоторые СУБД / версии имеют специальную оптимизацию, для
SELECT COUNT(*)
которой используются более быстрые опции, в то время как другие просто сканируют таблицы. Вам нужно будет перейти на сайты документации / поддержки для второго набора, который, вероятно, потребует написания более конкретного запроса, обычно такого, который каким-то образом попадает в индекс.РЕДАКТИРОВАТЬ:
Вот мысль, которая может сработать, в зависимости от вашей схемы и распределения данных: есть ли у вас индексированный столбец, который ссылается на возрастающее значение, числовой возрастающий идентификатор, скажем, или даже на временную метку или дату? Затем, при условии, что удаления не произойдет, должна быть возможность сохранить счетчик до некоторого недавнего значения (вчерашняя дата, наибольшее значение идентификатора в некоторой недавней точке выборки) и добавить счетчик сверх этого, который должен очень быстро разрешиться в индексе. , Конечно, очень сильно зависит от значений и индексов, но применимо практически ко всем версиям любой СУБД.
источник
SELECT COUNT(*)
. Даже MySQL, очевидно, делает это ...Я опоздал на этот вопрос, но вот что вы можете сделать с MySQL (поскольку я использую MySQL). Я делюсь своими наблюдениями здесь:
Результат Количество строк
: 508534 Вывод на
консоль: Затронутые строки: 0 Найдено строк: 1 Предупреждения: 0 Продолжительность 1 запроса: 0,125 сек.
Требуется время для таблицы с большим количеством строк, но количество строк очень точное.
Результат
Количество строк : 511235 Вывод на
консоль: Затронутые строки: 0 Найдено строк: 1 Предупреждения: 0 Продолжительность 1 запроса: 0,250 сек. Резюме: Количество строк не является точным.
Результат
Количество строк : 507806 Вывод на
консоль: Затронутых строк: 0 Найдено строк: 48 Предупреждений: 0 Продолжительность 1 запроса: 1,701 сек.
Количество строк не является точным.
Я не MySQL или эксперт по базам данных, но я обнаружил, что для очень больших таблиц вы можете использовать вариант 2 или 3 и получить «точное представление» о количестве присутствующих строк.
Мне нужно было получить количество строк для отображения некоторых статистических данных в пользовательском интерфейсе. С помощью вышеупомянутых запросов я знал, что общее количество строк было более 500 000, поэтому я придумал показывать статистику типа «Более 500 000 строк» без точного количества строк.
Возможно, я действительно не ответил на вопрос ОП, но я делюсь тем, что я сделал в ситуации, когда такая статистика была необходима. В моем случае показ приблизительных рядов был приемлемым, и вышеописанное помогло мне.
источник
Не совсем независимое от СУБД решение, но, по крайней мере, ваш клиентский код не увидит разницы ...
Создайте другую таблицу T с одной строкой и одним целочисленным полем N 1 и создайте INSERT TRIGGER, который просто выполняет:
Также создайте DELETE TRIGGER, который выполняет:
СУБД, достойная своей соли, будет гарантировать атомарность операций выше 2 , а N будет всегда содержать точное количество строк, которое потом будет очень быстро получить:
Хотя триггеры зависят от СУБД, выбор из T не обязателен, и ваш клиентский код не нужно будет менять для каждой поддерживаемой СУБД.
Тем не менее, это может иметь некоторые проблемы с масштабируемостью, если таблица является INSERT или DELETE-интенсивной, особенно если вы не делаете COMMIT сразу после INSERT / DELETE.
1 Эти имена просто заполнители - используйте что-то более значимое в производстве.
2 Т.е. N не может быть изменено одновременной транзакцией между чтением и записью в N, если и чтение, и запись выполняются в одном операторе SQL.
источник
Буквально безумный ответ, но если у вас настроена какая-то система репликации (я надеюсь, что для системы с миллиардом строк), вы можете использовать приблизительную оценку (например,
MAX(pk)
), разделить это значение на число подчиненных у вас есть, запустить несколько запросов параллельно.По большей части вы будете распределять запросы между подчиненными на основе лучшего ключа (или, я полагаю, первичного ключа) таким образом (мы будем использовать 250000000 в качестве наших рядов / подчиненных):
Но вам нужен только SQL. Что за бюст. Хорошо, так скажем, вы садомазохист. На главном (или ближайшем подчиненном) вам, скорее всего, нужно создать таблицу для этого:
Таким образом, вместо того, чтобы иметь только выборки, запущенные в ваших ведомых устройствах, вам нужно будет выполнить вставку, похожую на эту:
Вы можете столкнуться с проблемами при записи рабов в таблицу на ведущем устройстве. Вам может понадобиться еще больше садисов - я имею в виду, творческий подход:
В конце концов у вас должен быть ведомый, который существует последним на пути, пройденном графом репликации, относительно первого ведомого. Это ведомое устройство должно теперь иметь все другие значения счетчика и иметь свои собственные значения. Но к тому времени, как вы закончите, вероятно, будут добавлены строки, так что вам нужно будет вставить еще одну, компенсирующую записанный max pk в вашей counter_table и текущий max pk.
На этом этапе вам нужно было бы выполнить агрегатную функцию, чтобы выяснить, каково общее количество строк, но это проще, так как вы будете запускать его не более чем на «число ведомых устройств, которые вы имеете и меняете».
Если вы находитесь в ситуации, когда у вас есть отдельные таблицы в ведомых устройствах, вы можете
UNION
получить все необходимые вам строки.Или, знаете, будьте немного безумнее и перенесите свои данные в систему распределенной обработки, или, возможно, воспользуйтесь решением для хранилища данных (которое в будущем также даст вам потрясающий перебор данных).
Обратите внимание, это зависит от того, насколько хорошо настроена ваша репликация. Поскольку основным узким местом, скорее всего, будет постоянное хранилище, если у вас нечеткое хранилище или плохо сегрегированные хранилища данных с сильным шумом соседей, это, вероятно, будет работать медленнее, чем просто ожидание одного
SELECT COUNT(*) ...
Но если у вас хорошая репликация, то ваш прирост скорости должен быть напрямую связан с числом или рабами. Фактически, если для выполнения одного запроса подсчета требуется 10 минут, а у вас есть 8 подчиненных, вы бы сократили свое время до пары минут. Может быть, час, чтобы сгладить детали этого решения.
Конечно, вы никогда не получите действительно удивительно точного ответа, так как это распределенное решение вводит немного времени, когда строки могут быть удалены и вставлены, но вы можете попытаться получить распределенную блокировку строк в одном и том же экземпляре и получить точное количество строк в таблице на определенный момент времени.
На самом деле, это кажется невозможным, поскольку вы в основном застряли с решением только для SQL, и я не думаю, что у вас есть механизм, позволяющий мгновенно выполнять закрытый и заблокированный запрос для нескольких ведомых устройств. Возможно, если бы вы имели контроль над файлом журнала репликации ... это означает, что вы буквально раскручивали бы рабов для этой цели, что, без сомнения, медленнее, чем просто выполнение запроса подсчета на одной машине.
Так вот мои две копейки 2013 года.
источник
Если триггер вставки слишком дорогой в использовании, но триггер удаления может быть предоставлен, и имеется автоматическое увеличение
id
, то после однократного подсчета всей таблицы и запоминания счетчика какlast-count
иlast-counted-id
,затем каждый день просто нужно рассчитывать на
id
>last-counted-id
, добавить этоlast-count
и сохранить новыйlast-counted-id
.Триггер удаления уменьшит число последних записей, если идентификатор удаленной записи <= идентификатор последней записи.
источник
Если у вас есть типичная структура таблицы с автоинкрементным столбцом первичного ключа, в котором строки никогда не удаляются, следующий способ будет самым быстрым для определения количества записей и должен работать аналогично в большинстве совместимых с ANSI баз данных:
Я работаю с таблицами MS SQL, содержащими миллиарды строк, для которых требуется время отклика не более секунды для данных, включая количество записей. Подобный SELECT COUNT (*) может занять несколько минут для сравнения.
источник
INSERT
откат транзакции? Это значение первичного ключа будет отсутствовать, поэтому фактическое количество записей будет на единицу меньше максимального значения.count(*)
, если поставщик базы данных недостаточно оптимизированcount(*)
: каждый день отслеживайте последний автоиндекс и соответствующий ему счетчик, а затем запрашивайте количество записей за ним. Может также обрабатыватьdelete
s, если добавить при удалении триггер, который уменьшает предыдущий итог, если идентификатор удаленной записи <= этот последний автоиндекс.Для сервера Sql попробуйте это
источник
выберите строки из sysindexes, где id = Object_ID ('TableName') и indid <2
источник
Поместите индекс в какой-то столбец. Это должно позволить оптимизатору выполнить полное сканирование блоков индекса, а не полное сканирование таблицы. Это сократит ваши затраты на ввод-вывод. Посмотрите на план выполнения до и после. Затем измерьте время настенных часов в обоих направлениях.
источник
Если вы используете Oracle, как насчет этого (при условии, что статистика таблицы обновлена):
last_analyzed покажет время последней статистики.
источник
С PostgreSQL:
источник
В SQL Server 2016 я могу просто проверить свойства таблицы и затем выбрать вкладку «Хранилище» - это дает мне количество строк, дисковое пространство, используемое таблицей, индексное пространство и т. Д.
источник
database vendor independent solution
. Также это требует графического интерфейса и не может быть автоматизирован. Также это не быстрее, чем COUNT (*)Может быть немного поздно, но это может помочь другим для MSSQL
источник