2010-07-01 2 views
0

Я выборки данных для моей сетки, как этогопроектирование баз данных пейджинговой

SELECT 
    Orders.CustomerID, 
    Orders.OrderTime, 
    OrderItems.ProductID, 
    OrderItems.Quantity 
    FROM 
    dbo.Orders INNER JOIN dbo.OrderItems 
     ON Orders.ID = OrderItems.OrderID 

Мне также нужно общее количество для пагинации.

Существует два варианта.

1- сделать другой выборки

SELECT count(*) FROM dbo.Orders 

2- Поместите счета заявление в запросе

SELECT 
    Orders.CustomerID, 
    Orders.OrderTime, 
    OrderItems.ProductID, 
    OrderItems.Quantity, 
    (SELECT count(*) FROM dbo.Orders) as Count 
    FROM 
    dbo.Orders INNER JOIN dbo.OrderItems 
     ON Orders.ID = OrderItems.OrderID 

Какой путь я должен идти?

ответ

2

Из двух методов, которые вы выдвинули, первый (отдельный запрос) лучше. Второй метод означает, что счет будет отображаться в каждой возвращаемой строке, что немного не нужно. Также, если запрос возвращает 20 строк, select count(*) будет выполняться 20 раз (если я правильно помню, предположим, это может зависеть от того, какой механизм базы данных вы используете).

Кроме того, в зависимости от того, сколько трафика вы планируете и насколько большой стол может получить, вы можете улучшить это, кэшируя результат select count(*) где-нибудь, а затем обновляя его при вставках/удалениях в таблицу.

+0

Кроме того, вы должны использовать «LIMIT», чтобы получить только нужные вам записи. Это рекомендуется при выполнении поискового вызова. Сначала вы выполняете запрос с подсчетом, затем выполняете запрос с лимитом на основе «страницы» и «счет» (который определяет максимально возможную страницу) и размера страницы. – Alxandr

1

Если вы используя oracle вы можете использовать COUNT(*) OVER () CNT. Это один был более эффективным , как он принимает одну таблицу сканирования

SELECT 
    Orders.CustomerID, 
    Orders.OrderTime, 
    OrderItems.ProductID, 
    OrderItems.Quantity, 
    COUNT(*) OVER () CNT as Count 
    FROM 
    dbo.Orders INNER JOIN dbo.OrderItems 
     ON Orders.ID = OrderItems.OrderID 
1

Как @Mailslut предполагает, вы, вероятно, следует использовать два запроса. Тем не менее, вероятно, вы должны добавить в запрос, который извлекает данные, WHERE, поэтому вы получаете только данные, которые вам действительно нужно показывать (если вы не кешируете их).

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

1

Я бы подумал о чем-то другом, потому что то, что вы пытаетесь сделать, не очень просто, но совершенно необходимо. Считаете ли вы использование функции row_number SQL Server? Таким образом вы будете знать, сколько записей есть, посмотрев на max row_number, но также и в том порядке, в котором вы хотите.

SELECT 
    Orders.CustomerID, 
    Orders.OrderTime, 
    OrderItems.ProductID, 
    OrderItems.Quantity, 
    ROW_NUMBER() OVER(ORDER BY Orders.CustomerId) rn 
    FROM 
    dbo.Orders INNER JOIN dbo.OrderItems 
     ON Orders.ID = OrderItems.OrderID 
2

Если это для SQL Server 2005 или выше, один из лучших способов получить пагинацию является использование Common Table Expression.

CREATE PROC MyPaginatedDataProc 
@pageNumber INT 
AS 

WITH OrdersCTE (CustomerID, OrderTime, ProductID, Quantity, RowNumber) 
AS 
(
    SELECT 
     Orders.CustomerID, 
     Orders.OrderTime, 
     OrderItems.ProductID, 
     OrderItems.Quantity, 
     ROW_NUMBER() OVER (ORDER BY OrderItems.OrderID) AS RowNumber 
    FROM 
     dbo.Orders INNER JOIN dbo.OrderItems ON Orders.ID = OrderItems.OrderID 
) 

SELECT 
    CustomerID, 
    OrderTime, 
    ProductId, 
    Quantity 
FROM 
    OrdersCTE 
WHERE 
    RowNumber BETWEEN (@pageNumber * 10) AND (((@pageNumber + 1) * 10) -1) 

В противном случае для получения общего количества строк я бы использовал отдельный запрос, например, Mailslut.