Access
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Access

Access nói chuyện với các nguồn dữ liệu ODBC như thế nào? Phần 5

Lọc tập bản ghi

Trong phần 5 của loạt bài này, chúng ta sẽ tìm hiểu cách Microsoft Access xử lý các bộ lọc đã triển khai và tích hợp chúng vào các truy vấn ODBC. Trong bài viết trước, chúng ta đã biết cách Access sẽ hình thành SELECT các câu lệnh trong lệnh ODBC SQL. Chúng ta cũng đã biết trong bài viết trước về cách Access sẽ cố gắng cập nhật một hàng bằng cách áp dụng WHERE mệnh đề dựa trên khóa và nếu có, đảo ngược. Tuy nhiên, chúng ta cần tìm hiểu cách Access sẽ xử lý các bộ lọc được cung cấp cho các truy vấn Access và dịch chúng trong lớp ODBC. Có các cách tiếp cận khác nhau mà Access có thể sử dụng tùy thuộc vào cách các truy vấn Access được xây dựng và bạn sẽ học cách dự đoán cách Access sẽ dịch một truy vấn Access thành một truy vấn ODBC cho các vị từ bộ lọc khác nhau đã cho.

Bất kể bạn thực sự áp dụng bộ lọc như thế nào - có thể là tương tác thông qua các lệnh ruy-băng của biểu mẫu hoặc biểu dữ liệu hoặc nhấp chuột vào menu bên phải, hoặc sử dụng VBA theo chương trình hoặc chạy các truy vấn đã lưu - Access sẽ đưa ra một truy vấn ODBC SQL tương ứng để thực hiện lọc. Nói chung, Access sẽ cố gắng lọc từ xa nhiều nhất có thể. Tuy nhiên, nó sẽ không cho bạn biết nếu nó không thể làm như vậy. Thay vào đó, nếu Access không thể thể hiện bộ lọc bằng cú pháp ODBC SQL, thay vào đó, nó sẽ cố gắng tự thực hiện lọc bằng cách tải xuống toàn bộ nội dung của bảng và đánh giá điều kiện cục bộ. Điều đó có thể giải thích tại sao đôi khi bạn có thể gặp phải một truy vấn chạy nhanh nhưng chỉ với một thay đổi nhỏ, việc thu thập thông tin lại bị chậm lại. Phần này hy vọng sẽ giúp bạn hiểu khi nào điều này có thể xảy ra và cách xử lý để bạn có thể giúp Access từ xa càng nhiều càng tốt vào các nguồn dữ liệu để áp dụng bộ lọc.

Đối với bài viết này, chúng tôi sẽ sử dụng các truy vấn đã lưu nhưng thông tin thảo luận ở đây vẫn sẽ áp dụng cho các phương pháp áp dụng bộ lọc khác.

Bộ lọc tĩnh

Chúng tôi sẽ bắt đầu dễ dàng và tạo một truy vấn đã lưu bằng bộ lọc được mã hóa cứng.

SELECT 
   c.CityID
  ,c.CityName
  ,c.StateProvinceID
FROM Cities AS c
WHERE c.CityName="Boston";
Nếu chúng ta mở truy vấn, chúng ta sẽ thấy ODBC SQL này trong dấu vết:

SQLExecDirect: 
SELECT "c"."CityID" 
FROM "Application"."Cities" "c" 
WHERE ("CityName" = 'Boston' ) 
Ngoài những thay đổi trong cú pháp, ngữ nghĩa của truy vấn không thay đổi; cùng một bộ lọc được chuyển vào nguyên trạng. Lưu ý rằng chỉ CityID được chọn bởi vì theo mặc định, một truy vấn sử dụng một tập bản ghi kiểu dynaset mà chúng ta đã thảo luận ở phần trước.

Bộ lọc được tham số hóa đơn giản

Hãy thay đổi SQL để sử dụng một tham số thay thế:

PARAMETERS SelectedCityName Text ( 255 );
SELECT 
  c.CityID
 ,c.CityName
 ,c.StateProvinceID
FROM Cities AS c
WHERE c.CityName=[SelectedCityName];
Nếu chúng tôi chạy truy vấn và nhập “Boston” trong giá trị dấu nhắc tham số như được hiển thị, chúng tôi sẽ thấy SQL theo dõi ODBC sau:
SQLExecDirect: 
SELECT "c"."CityID" 
FROM "Application"."Cities" "c" 
WHERE ("CityName" =  ? ) 
Lưu ý rằng chúng ta sẽ quan sát cùng một hành vi với các tham chiếu điều khiển hoặc liên kết biểu mẫu con. Nếu chúng tôi sử dụng cái này để thay thế:

SELECT 
   c.CityID
  ,c.CityName
  ,c.StateProvinceID
FROM Cities AS c
WHERE c.CityName=[Forms]![frmSomeForm]![txtSomeText];
Chúng tôi sẽ vẫn nhận được ODBC SQL được theo dõi giống như chúng tôi đã thấy với truy vấn tham số ban đầu. Đó vẫn là trường hợp mặc dù truy vấn đã sửa đổi của chúng tôi không có PARAMETERS tuyên bố. Điều này cho thấy Access có thể nhận ra rằng các tham chiếu điều khiển có thể thay đổi giá trị của nó theo thời gian, được coi là một tham số tốt nhất khi xây dựng ODBC SQL.

Điều đó cũng hoạt động cho chức năng VBA. Chúng ta có thể thêm một hàm VBA mới:

Public Function GetSelectedCity() As String
    GetSelectedCity = "Boston"
End Function
Chúng tôi điều chỉnh truy vấn đã lưu để sử dụng chức năng VBA mới:

WHERE c.CityName=GetSelectedCity();
Nếu bạn theo dõi điều này, bạn sẽ thấy rằng nó vẫn như cũ. Do đó, chúng tôi đã chứng minh rằng bất kể đầu vào là tham số rõ ràng, tham chiếu đến điều khiển hay kết quả của hàm VBA, Access sẽ coi tất cả chúng như một tham số của truy vấn ODBC SQL mà nó sẽ thực thi trên thay mặt. Đó là một điều tốt vì nhìn chung, chúng tôi nhận được hiệu suất tốt hơn khi chúng tôi có thể sử dụng lại một truy vấn và chỉ cần thay đổi tham số.

Tuy nhiên, có một kịch bản phổ biến hơn mà các nhà phát triển Access thường thiết lập và đó là tạo SQL động với mã VBA, thường bằng cách nối một chuỗi và sau đó thực thi chuỗi đã nối. Hãy sử dụng mã VBA sau:

Public Sub GetSelectedCities()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim fld As DAO.Field
    
    Dim SelectedCity As String
    Dim SQLStatement As String
    
    SelectedCity = InputBox("Enter a city name")
    SQLStatement = _
        "SELECT c.CityID, c.CityName, c.StateProvinceID " & _
        "FROM Cities AS c " & _
        "WHERE c.CityName = '" & SelectedCity & "';"
    
    Set db = CurrentDb
    Set rs = db.OpenRecordset(SQLStatement)
    Do Until rs.EOF
        For Each fld In rs.Fields
            Debug.Print fld.Value;
        Next
        Debug.Print
        rs.MoveNext
    Loop
End Sub
ODBC SQL được theo dõi cho OpenRecordset như sau:

SQLExecDirect: 
SELECT "c"."CityID" 
FROM "Application"."Cities" "c" 
WHERE ("CityName" = 'Boston' ) 
Không giống như các ví dụ trước, ODBC SQL không được tham số hóa. Access không có cách nào để biết rằng ‘Boston’ đã được điền động vào thời gian chạy bởi một VBA.InputBox . Chúng tôi chỉ đưa cho nó SQL được xây dựng từ Access ’POV, chỉ là một câu lệnh SQL tĩnh. Trong trường hợp này, chúng tôi đánh bại tham số hóa của truy vấn. Điều quan trọng là phải nhận ra rằng một lời khuyên phổ biến được đưa ra cho các nhà phát triển Access là SQL được xây dựng động tốt hơn so với việc sử dụng truy vấn tham số vì nó tránh được vấn đề trong đó công cụ Access có thể tạo kế hoạch thực thi dựa trên một giá trị tham số có thể thực sự không tối ưu cho một giá trị khác Giá trị tham số. Để biết thêm chi tiết về hiện tượng đó, tôi khuyến khích bạn đọc về vấn đề “đánh hơi tham số”. Lưu ý rằng đây là vấn đề chung đối với bất kỳ công cụ cơ sở dữ liệu nào, không chỉ Access. Tuy nhiên, trong trường hợp của Access, SQL động hoạt động tốt hơn vì chỉ cần tạo một kế hoạch thực thi mới rẻ hơn nhiều. Ngược lại, công cụ RDBMS có thể có các chiến lược bổ sung để xử lý vấn đề và có thể nhạy cảm hơn với việc có quá nhiều kế hoạch thực hiện một lần vì điều đó có thể tác động tiêu cực đến bộ nhớ đệm của nó.

Vì lý do đó, các truy vấn được tham số hóa từ Access chống lại các nguồn ODBC có thể được ưu tiên hơn so với SQL động. Vì Access sẽ coi các điều khiển tham chiếu trên biểu mẫu hoặc các hàm VBA không yêu cầu tham chiếu cột làm tham số, bạn không cần tham số rõ ràng trong nguồn bản ghi hoặc nguồn hàng của mình. Tuy nhiên, nếu bạn đang sử dụng VBA để thực thi SQL, thông thường tốt hơn là sử dụng ADO, hỗ trợ tốt hơn nhiều cho việc tham số hóa. Trong trường hợp tạo nguồn bản ghi động hoặc nguồn hàng, sử dụng điều khiển ẩn trên biểu mẫu / báo cáo có thể là một cách dễ dàng để tham số hóa truy vấn. Tuy nhiên, nếu truy vấn có sự khác biệt rõ rệt, việc xây dựng SQL động trong VBA và gán nó cho thuộc tính nguồn bản ghi / nguồn hàng có hiệu quả buộc phải biên dịch lại đầy đủ và do đó tránh sử dụng các kế hoạch thực thi không tốt sẽ không hoạt động tốt cho tập hợp đầu vào hiện tại. Bạn có thể tìm thấy các đề xuất trong bài viết thảo luận về WITH RECOMPILE của SQL Server hữu ích trong việc quyết định có buộc biên dịch lại hay không sử dụng truy vấn được tham số hóa.

Sử dụng các hàm trong lọc SQL

Trong phần trước, chúng ta đã thấy rằng một câu lệnh SQL chứa hàm VBA được tham số hóa để Access có thể thực thi hàm VBA và sử dụng đầu ra làm đầu vào cho truy vấn được tham số hóa. Tuy nhiên, không phải tất cả các hàm tích hợp đều hoạt động theo cách này. Hãy sử dụng UCase() làm ví dụ để lọc truy vấn. Hơn nữa, chúng tôi sẽ áp dụng hàm trên một cột.

SELECT 
   c.CityID
  ,c.CityName
  ,c.StateProvinceID
FROM Cities AS c
WHERE UCase([c].[CityName])="BOSTON";
Nếu chúng ta nhìn vào ODBC SQL được theo dõi, chúng ta sẽ thấy điều này:

SQLExecDirect: 
SELECT "c"."CityID" 
FROM "Application"."Cities" "c" 
WHERE ({fn ucase("CityName" )}= 'BOSTON' )
Trong ví dụ trước, Access có thể tham số hóa hoàn toàn GetSelectedCity() vì nó không yêu cầu đầu vào từ các cột được tham chiếu trong truy vấn. Tuy nhiên, UCase() yêu cầu đầu vào. Chúng tôi đã cung cấp UCase("Boston") , Access cũng sẽ tham số hóa điều này. Tuy nhiên, đầu vào là tham chiếu cột, Access không thể tham số hóa dễ dàng. Tuy nhiên, Access có thể phát hiện ra rằng UCase() là một trong những hàm vô hướng ODBC được hỗ trợ. Vì chúng tôi muốn loại bỏ nguồn dữ liệu càng nhiều càng tốt, Access sẽ thực hiện điều đó bằng cách gọi phiên bản ucase của ODBC .

Nếu sau đó chúng ta tạo một hàm VBA tùy chỉnh mô phỏng UCase() chức năng:

Public Function MyUCase(InputValue As Variant) As String
    MyUCase = UCase(InputValue)
End Function
và thay đổi bộ lọc trong truy vấn thành:

WHERE MyUCase([c].[CityName])="BOSTON";
Đây là những gì chúng tôi nhận được:

SQLExecDirect: 
SELECT 
   "CityName"
  ,"c"."CityID" 
FROM "Application"."Cities" "c" 
Access không thể điều khiển từ xa chức năng VBA tùy chỉnh MyUCase trở lại nguồn dữ liệu. Tuy nhiên, SQL của truy vấn đã lưu là hợp pháp nên Access phải đáp ứng bằng cách nào đó. Để thực hiện việc này, nó sẽ kết thúc việc tải xuống toàn bộ CityNameCityID tương ứng của nó để chuyển vào hàm VBA MyUCase() và đánh giá kết quả. Do đó, truy vấn hiện hoạt động chậm hơn nhiều vì Access hiện đang yêu cầu nhiều dữ liệu hơn và thực hiện nhiều công việc hơn.

Mặc dù chúng tôi đã sử dụng UCase() trong ví dụ này, rõ ràng chúng ta có thể thấy rằng tốt hơn hết là làm việc từ xa càng nhiều càng tốt với nguồn dữ liệu. Nhưng điều gì sẽ xảy ra nếu chúng ta có một hàm VBA phức tạp không thể viết lại thành phương ngữ SQL gốc của nguồn dữ liệu? Mặc dù tôi nghĩ rằng trường hợp này khá hiếm, nhưng nó đáng để xem xét. Giả sử rằng chúng ta có thể thêm một bộ lọc để thu hẹp tập hợp các thành phố được trả lại.

SELECT 
   c.CityID
  ,c.CityName
  ,c.StateProvinceID
FROM Cities AS c
WHERE c.CityName LIKE "Bos*"
  AND MyUCase([c].[CityName])="BOSTON";
ODBC SQL được theo dõi sẽ xuất hiện như sau:

SQLExecDirect: 
SELECT 
   "CityName"
  ,"c"."CityID" 
FROM "Application"."Cities" "c" 
WHERE ("CityName" LIKE 'Bos%' ) 
Quyền truy cập có thể điều khiển từ xa LIKE quay lại nguồn dữ liệu, dẫn đến việc lấy lại tập dữ liệu nhỏ hơn nhiều. Nó sẽ vẫn thực hiện đánh giá cục bộ của MyUCase() trên tập dữ liệu kết quả. Truy vấn chạy nhanh hơn nhiều chỉ đơn giản là do tập dữ liệu nhỏ hơn được trả về.

Điều này cho chúng ta biết nếu chúng ta phải đối mặt với tình huống không mong muốn trong đó chúng ta không thể dễ dàng cấu trúc lại một hàm VBA phức tạp từ một truy vấn, chúng ta vẫn có thể giảm thiểu các tác động xấu bằng cách thêm các bộ lọc có thể được điều khiển từ xa để giảm tập hợp các bản ghi ban đầu để Access làm việc với.

Lưu ý về khả năng phân loại

Trong các ví dụ trước, chúng tôi đã áp dụng một hàm vô hướng trên một cột. Điều đó có khả năng hiển thị truy vấn là "không phân chia được", có nghĩa là công cụ cơ sở dữ liệu không thể tối ưu hóa truy vấn bằng cách sử dụng chỉ mục để tìm kiếm và tìm các kết quả phù hợp. Phần “sarg” của từ “sargability” đề cập đến “Search ARGument”. Giả sử chúng ta có chỉ mục được xác định tại nguồn dữ liệu trên bảng:

CREATE INDEX IX_Cities_CityName
ON Application.Cities (CityName);
Các biểu thức như UCASE(CityName) ngăn công cụ cơ sở dữ liệu không thể sử dụng chỉ mục IX_Cities_CityName bởi vì công cụ buộc phải đánh giá từng hàng một để tìm kết quả phù hợp, giống như Access đã làm với hàm VBA tùy chỉnh. Một số công cụ cơ sở dữ liệu chẳng hạn như các phiên bản gần đây của SQL Server hỗ trợ tạo chỉ số dựa trên một biểu thức. Nếu chúng tôi muốn tối ưu hóa các truy vấn bằng cách sử dụng UCASE() hàm transact-SQL, chúng tôi có thể điều chỉnh định nghĩa chỉ mục:

CREATE INDEX IX_Cities_Boston_Uppercase
ON Application.Cities (CityName)
WHERE UCASE(CityName) = 'BOSTON';
Điều này cho phép SQL Server xử lý truy vấn bằng WHERE UCase(CityName) = 'BOSTON' như một truy vấn có thể phân loại được vì nó hiện có thể sử dụng chỉ mục IX_Cities_Boston_Uppercase để trả về các bản ghi phù hợp. Tuy nhiên, nếu truy vấn khớp trên 'CLEVELAND' thay vì 'BOSTON' , tính nổi bật bị mất.

Bất kể công cụ cơ sở dữ liệu nào bạn đang thực sự làm việc, bạn luôn nên thiết kế và sử dụng các truy vấn có thể phân loại ở bất kỳ nơi nào có thể để tránh các vấn đề về hiệu suất. Các truy vấn quan trọng phải có các chỉ số bao trùm để mang lại hiệu suất tốt nhất. Tôi khuyến khích bạn nghiên cứu thêm về khả năng phân loại và các chỉ số bao hàm để giúp bạn tránh thiết kế các truy vấn trên thực tế là không thể phân loại.

Kết luận

Chúng tôi đã xem xét cách Access xử lý việc áp dụng bộ lọc từ Access SQL vào các truy vấn ODBC. Chúng tôi cũng đã khám phá các trường hợp khác nhau trong đó Access sẽ chuyển đổi các loại tham chiếu khác nhau thành một tham số, cho phép Access thực hiện đánh giá bên ngoài lớp ODBC và chuyển chúng dưới dạng đầu vào vào câu lệnh ODBC đã chuẩn bị. Chúng tôi cũng đã xem xét điều gì sẽ xảy ra khi nó không thể được tham số hóa, thường là do chứa các tham chiếu cột làm đầu vào. Điều đó có thể gây ra hậu quả về hiệu suất trong quá trình di chuyển sang máy chủ SQL.

Đối với một số hàm nhất định, Access có thể chuyển đổi biểu thức để sử dụng các hàm vô hướng ODBC, điều này cho phép Access điều khiển biểu thức từ xa tới nguồn dữ liệu ODBC. Một phân nhánh của điều này là nếu việc triển khai hàm vô hướng khác nhau, nó có thể khiến truy vấn hoạt động khác hoặc có thể hoạt động nhanh hơn / chậm hơn. Chúng tôi đã thấy cách một hàm VBA, ngay cả một hàm đơn giản bao bọc một hàm vô hướng có thể điều khiển từ xa khác có thể đánh bại nỗ lực điều khiển biểu thức từ xa. Chúng tôi cũng biết rằng nếu chúng tôi gặp trường hợp không thể cấu trúc lại một hàm VBA phức tạp từ truy vấn Access / nguồn ghi / nguồn hàng, thì ít nhất chúng tôi có thể giảm thiểu việc tải xuống tốn kém bằng cách thêm các bộ lọc bổ sung trên truy vấn có thể được khởi động từ xa để giảm số lượng dữ liệu được trả về.

Trong bài tiếp theo, chúng ta sẽ xem xét cách Access xử lý các phép nối.

Tìm kiếm trợ giúp với Microsoft Access? Gọi cho các chuyên gia của chúng tôi ngay hôm nay theo số 773-809-5456 hoặc gửi email cho chúng tôi theo địa chỉ [email protected].


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Trình đơn truy cập thả xuống TreeView ImageCombo

  2. Tiếp cận quan điểm của các chuyên gia trong Hội nghị thượng đỉnh MVP 2020

  3. 4 loại thông tin cần đưa vào cơ sở dữ liệu CRM của bạn

  4. Mẹo về Bảng Microsoft Access - Thủ thuật &Nguyên tắc Phần 5

  5. Mô-đun lớp MS-Access và VBA