Какой самый быстрый способ выбрать строки из огромной базы данных? - PullRequest
0 голосов
/ 19 марта 2012

У меня огромная база данных, содержащая более 3 миллионов строк (информация о моих пользователях), мне нужно выбрать всех пользователей, у которых есть дни рождения в текущий день.

Столбец дня рождения представляет собой text (например, «19/03» или «19/03/1975») с указанием дня и месяца, а иногда и лет.

Когда я пытаюсь выбрать строки с похожими функциями слева, для возврата результатов требуется больше минуты.

Я попытался использовать столбец 3 int для day, month и year, а затем сделать выбор, но для получения результатов потребовалось больше времени.

Есть идеи, как заставить его работать быстрее?

Я использую SQL Server 2008

Спасибо

Ответы [ 4 ]

2 голосов
/ 19 марта 2012

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

Наконец - и этобольшой.TEXT - это наихудший тип данных, который вы можете выбрать.Как хранится текст, данные на самом деле не хранятся на самой странице.Вместо этого он оставляет 16-байтовый указатель на другую страницу.Эта другая страница будет содержать сами данные в записи.Но что еще хуже, эта запись будет представлять собой тип данных SMALL_ROOT, занимающий 84 байта, когда ваши данные имеют длину от 0 до 64 байтов!

Таким образом, то, что могло быть сохранено как 8-байтовая дата / времяили 4-байтовая дата теперь занимает в общей сложности 100 байтов и вызывает поиск вне строки для каждой строки.По сути, идеальный шторм для плохой работы.

Если вы не можете изменить его на более подходящее время, по крайней мере, замените его на varchar!

1 голос
/ 19 марта 2012

прежде всего сохраните дату в формате, который поддерживается SQL Server, например, DATE или DATETIME (в вашем случае, я думаю, вам достаточно DATE), как только у вас появится возможность использовать функции SQL например, MONTH и DAY, как показано ниже, и избегайте сложной функции манипуляции со строками, такой как ВЛЕВО и т. д.

Ваш запрос будет выглядеть так:

select * from MyTable where MONTH(dateColumnA) = '1' && DAY(dateColumnB) ='7' --1 is for january

Я не уверен, что это полностью решит ваши проблемы с производительностью, но вы можете запустить этот запрос в SQL Query Analyzer и посмотреть, какие рекомендации он дает в отношении индексов и т. Д. У меня нет достаточных знаний об индексах для типа Date столбцы

0 голосов
/ 19 марта 2012

Попробуйте использовать Result Set вместо DataTable или DataSet. ResultSet быстр по сравнению с обоими

0 голосов
/ 19 марта 2012

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

CREATE INDEX IX_MyTable_Date_Ints ON MyTable(intYear, intMonth, intDay)
CREATE INDEX IX_MyTable_Date ON MyTable(BirthDate)

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

Затем вы можете искать день рождения независимо от года.без необходимости вызывать функцию для каждой записи, добавив "WHERE birth_day = '3004-12-10'. Если это поле проиндексировано, вы должны иметь возможность вернуть все совпадающие строки во флэш-памяти.Имейте в виду, что при поиске в индексе серверу нужно будет выполнить не более 32 сравнений, чтобы найти совпадение в записях из 4 млрд. Никогда не стоит недооценивать преимущества индексирования!триггер, чтобы он постоянно обновлялся. Для тех дат рождения, где у вас нет года, просто используйте свой базовый год (3004.) Поскольку ваш базовый год находится в будущем, вы знаете, что эта дата рождения неиметь год.

CREATE TABLE MyTable (
    MyTable_key INT IDENTITY(1, 1),
    username VARCHAR(30),
    birth_date DATE,
    birth_day DATE
)
ALTER TABLE MyTable ADD CONSTRAINT PK_MyTable PRIMARY KEY CLUSTERED (MyTable_key)
CREATE INDEX MyTable_birth_date ON MyTable(birth_date)
CREATE INDEX MyTable_birth_day ON MyTable(birth_day)
GO
CREATE TRIGGER tr_MyTable_calc_birth_day ON MyTable AFTER INSERT, UPDATE AS
    UPDATE t SET birth_day = DATEADD(YEAR, 3004-DATEPART(YEAR, t.birth_date), t.birth_date)
    FROM MyTable t, inserted i WHERE i.MyTable_key = t.MyTable_key

Чтобы обновить существующую таблицу, запустите обновление как отдельный запрос, без объединения с модулями.Таблица ошибок, как она использовалась в триггере:

    UPDATE MyTable SET birth_day = DATEADD(YEAR, 3004-DATEPART(YEAR, birth_date), birth_date)

Надеюсь, это поможет.

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