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