Hệ thống đặt món theo khoảng cách [Dựa trên tọa độ vĩ độ và kinh độ] Sắp xếp và Tìm kiếm

Bài viết này trình bày quá trình tối ưu hóa tính năng tìm kiếm và sắp xếp nhà hàng theo khoảng cách trong hệ thống đặt món. Bài viết sẽ đi sâu vào thiết kế cơ sở dữ liệu, các giải pháp từng được áp dụng qua các năm và đề xuất giải pháp cải tiến cuối cùng.

Thiết kế cơ sở dữ liệu

  • ETogo: Bảng thông tin nhà hàng (dataid - mã nhà hàng, togoname - tên nhà hàng)
  • ETogoLocalInfo: Bảng lưu trữ tọa độ (togoid - khóa ngoại, lat - vĩ độ, lng - kinh độ)
  • EAddress: Bảng địa chỉ người dùng (lat - vĩ độ, lng - kinh độ)

Giải pháp năm 2010

public List<TogoInfo> LayDanhSachTheoKhoangCach(int pageSize, int pageIndex, string dieuKien, string cotSapXep, int loaiSapXep, string vido, string kinhdo) {
    List<TogoInfo> danhSach = new List<TogoInfo>();
    string danhSachID = "";
    
    if(pageIndex > 1) {
        danhSachID = LayIDTheoKhoangCach(pageSize, pageIndex, dieuKien, cotSapXep, loaiSapXep, vido, kinhdo);
        if(string.IsNullOrEmpty(danhSachID)) return danhSach;
    }
    
    SqlParameter[] thamSo = new SqlParameter[9];
    thamSo[0].Value = "etogo";
    string truong = "*, (select Lat from ETogoLocalInfo where togoid = etogo.dataid) as lat ,(select lng from ETogoLocalInfo where togoid = etogo.dataid) as lng, ";
    truong += "(( 6371 * acos( cos( radians(" + vido + ") ) * cos( radians( (select Lat from ETogoLocalInfo where togoid = etogo.dataid) )) * cos( radians( (select lng from ETogoLocalInfo where togoid = etogo.dataid) ) - radians(" + kinhdo + ") ) + sin( radians(" + vido + ") ) * sin( radians( (select Lat from ETogoLocalInfo where togoid = etogo.dataid) ) ) ) )) as KhoangCach ";
    
    thamSo[1].Value = truong;
    // ... (phần còn lại của mã được giữ nguyên cấu trúc nhưng đổi tên biến)
}

Lưu trữ phân trang

CREATE PROCEDURE pageselectpri_togo
    @tblName varchar(255),
    @strGetFields varchar(1000) = '*',
    @primary varchar(255)='',
    @orderName varchar(255)='',
    @PageSize int = 10,
    @PageIndex int = 1,
    @OrderType bit = 0,
    @strWhere varchar(1500) = '',
    @ids varchar(2000)
AS
BEGIN
    DECLARE @strSQL varchar(5000), @strTmp varchar(110), @strOrder varchar(400)
    
    IF @OrderType != 0
    BEGIN
        SET @strTmp = ' not in (select '
        SET @strOrder = ' order by ' + @orderName +' desc'
        IF @orderName <> @primary
            SET @strOrder = @strOrder + ',[' + @primary +'] desc'
    END
    ELSE
    BEGIN
        SET @strTmp = ' not in (select '
        SET @strOrder = ' order by ' + @orderName +' asc'
        IF @orderName <> @primary
            SET @strOrder = @strOrder + ',[' + @primary +'] asc'
    END
    
    IF @PageIndex = 1
        SET @strSQL = 'select top ' + str(@PageSize) +' '+@strGetFields+ '  from [' + @tblName + '] where ' + @strWhere + ' ' + @strOrder
    ELSE
        SET @strSQL = 'select top ' + str(@PageSize) +' '+@strGetFields+ '  from [' + @tblName + '] where [' + @primary + '] not in (' + @ids + ') and ' + @strWhere + ' ' + @strOrder
    
    EXEC (@strSQL)
END

Giải pháp năm 2013 (Tối ưu hóa cuối cùng)

CREATE PROCEDURE ETogo_GetShopListWithDistance
    @pageSize int,
    @pageIndex int,
    @cotSapXep varchar(20),
    @loaiSapXep varchar(5),
    @dieuKien varchar(2000),
    @vido VARCHAR(50),
    @kinhdo VARCHAR(50),
    @dieukienKhoangcach VARCHAR(2000)
AS
BEGIN
    DECLARE @startRow int, @endRow int, @sql nvarchar(4000), @cotSapXepCuThe nvarchar(200)
    
    SET @cotSapXepCuThe = '( 6371 * acos( cos( radians(' + @vido + ') ) * cos( radians( Lat )) * cos( radians( lng ) - radians(' + @kinhdo + ') ) + sin( radians(' + @vido + ') ) * sin( radians( Lat ) ) ) )'
    
    IF @dieukienKhoangcach = ''
        SET @dieukienKhoangcach = '1=1'
    
    SET @startRow = (@pageIndex - 1) * @pageSize + 1
    SET @endRow = @startRow + @pageSize - 1
    
    SET @sql = '
        SELECT * FROM (
            SELECT *, ROW_NUMBER() OVER(ORDER BY ' + @cotSapXep + ' ' + @loaiSapXep + ') AS [stt] FROM (
                SELECT ' + @cotSapXepCuThe + ' AS khoangcach, etogo.*, ETogoLocalInfo.Lat, ETogoLocalInfo.Lng,
                CASE WHEN (CONVERT(varchar(12), Time1Start, 114) < CONVERT(varchar(12), getdate(), 114) AND 
                          CONVERT(varchar(12), Time1End, 114) > CONVERT(varchar(12), getdate(), 114)) OR 
                         (CONVERT(varchar(12), Time2Start, 114) < CONVERT(varchar(12), getdate(), 114) AND 
                          CONVERT(varchar(12), Time2End, 114) > CONVERT(varchar(12), getdate(), 114)) THEN 1 ELSE 0 END AS hoatdong
                FROM etogo
                LEFT JOIN ETogoLocalInfo ON etogo.dataid = ETogoLocalInfo.togoid WHERE ' + @dieuKien + ' 
            ) m WHERE ' + @dieukienKhoangcach + ' 
        ) m2
        WHERE stt BETWEEN ' + CAST(@startRow AS VARCHAR) + ' AND ' + CAST(@endRow AS VARCHAR)
    
    PRINT @sql
    EXEC sp_executesql @sql
END

Giải pháp cuối cùng cho phép:

  • Tính toán khoảng cách bằng tham số @dieukienKhoangcach (ví dụ: khoangcach < 2)
  • Sắp xếp theo khoảng cách bằng @cotSapXep = 'khoangcach'
  • Không cần viết công thức tính khoảng cách trong ứng dụng
  • Kiểm tra trạng thái hoạt động của nhà hàng dựa trên giờ làm việc

Thẻ: SQL Server T-SQL Toán học vị trí Phân trang Hiệu suất cơ sở dữ liệu

Đăng vào ngày 6 tháng 7 lúc 09:46